is there a dataProviderChange event for dropdownlist? - actionscript-3

I have a case where the SelectedItem isn't called after the data provider changes for
a dropdownlist.
is there a way to detect if such a change occurred?
Thanks

Just about every public property in the Flex Framework has a 'propertyChanged' event that is dispatched from the properties set method. They are used primarily for binding purposes, but not usually formally documented.
The dataProvider set method of a DropDownList does indeed dispatch a dataProviderChanged event. The code is several layers up in the hierarchy, as part of SkinnableDataContainer or if the skin for your 'SkinnableDataContainer' has a dataGroup it is dispatched from the DataGroup.
But, this event will probably will not be exposed via code hinting in MXML. You'll have to listen for it in ActionScript:
myList.addEventListener('dataProviderChanged', onDataProviderChanged);
Keep in mind this event will always be dispatched when the dataProvider changes, regardless of what happens to the selectedItem property.

You can listen to changes in the selectedItem in a DropDownList through the IndexChangeEvent, illustrated by the code below:
<s:DropDownList id="dl_mydl"
dataProvider="{dataProvider}"
change="dropDownListChangeHandler(event)"
/>
protected function dropDownListChangeHandler(event:IndexChangeEvent) : void
{
//DO SOMETHING
}

Related

get inner component from flexGlobals.topLevelApplication

I feel the way inner components could be accessed be better than what I know.
I know we can access any inner component something like:
FlexGlobals.topLevelApplication.someChild1.someChild2.someChild3… and so on
I've a components which has number of parent components hierarchy. I wish to know if there could be anyway I could access the last child without referring all of its parent.
I need to trigger an event on that component.
FlexGlobals.topLevelApplication.child1.child2.child3.dispatchEvent(new Event('clearData', true));
Updated: I tried the way you suggested in point 1. I've added the event listener on child component and try to dispatch it from a action script file, but it went unheared.\
child3.addEventLisener('clearData', clearHandler);
And then I dispatched the event some thing like:
dispatchEvent(new Event(modelApp.CLEAR_PALETTE, true)
try to add
FlexGlobals.topLevelApplication.systemManger.addEventLisener('clearData', clearHandler);
in child3
and dispacthed it from any where you want,
for dispatching use the following
FlexGlobals.topLevelApplication.systemManager.dispatchEvent(new Event(modelApp.CLEAR_PALETTE, true)
How I understood from the question used no good principles of application design, but that's another question.
In your case, you can use stage as global currentTarget for bubbles events. Dispatch event from displayObject with bubbles = true; In target display object listen event with stage object with/out capture phase.
in any displayObject:
dispatchEvent(new Event("myEvent", true));
in target displayObject:
// add ADDED_TO_STAGE event listener in constructor or when component creation complete
protected function component_creationCompleteHandler(event:FlexEvent):void
{
addEventListener(Event.ADDED_TO_STAGE, onAddToStage);
}
..
protected function onAddToStage(event:Event):void
{
stage.addEventListener("myEvent", eventHandler, true);
}
protected function eventHandler(event:Event):void
{
trace("eventHandler");
}
It is better than use reference to FlexGlobals object. Code more flexible.
I think you should go down to the level of component and addEventListener on initialize.
and dispatch from where ever you want.
other way is to do that, you need to save component reference(ID) in object on creationComplete. save its refence in your model. now you can access it where ever you want. and do what ever you want.
i also did in this way, i saved my screen components refrence in an array and access it where i need to dynamically validate all components.
otherwise you need nested looping to got your required child.

Actionscript 3: Entire event dispatching becomes unusable

I'm working on something similar to the Angry Birds "rollout" for options, etc., but I'm running into a fairly substantial problem.
The rollout itself is just a toggle button, with several other buttons added to the display list that move when you touch the toggle button. Each of these buttons is a class that extends Sprite and contains individual methods for touch events, begin, end and out. When these buttons get initialized (NOT instantiated), the touch begin listener is added. Something like this:
public function Initialize():void
{
this.addEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin, false, int.MAX_VALUE);
}
private function OnTouchBegin(e:TouchEvent):void
{
this.removeEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin);
this.addEventListener(TouchEvent.TOUCH_END, OnTouchRelease, false, int.MAX_VALUE);
this.addEventListener(TouchEvent.TOUCH_OUT, OnTouchOut, false, int.MAX_VALUE);
}
private function OnTouchRelease(e:TouchEvent):void
{
this.addEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin, false, int.MAX_VALUE);
this.removeEventListener(TouchEvent.TOUCH_END, OnTouchRelease);
this.removeEventListener(TouchEvent.TOUCH_OUT, OnTouchOut);
}
private function OnTouchOut(e:TouchEvent):void
{
this.addEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin, false, int.MAX_VALUE);
this.removeEventListener(TouchEvent.TOUCH_END, OnTouchRelease);
this.removeEventListener(TouchEvent.TOUCH_OUT, OnTouchOut);
}
Then, when these buttons get hidden from the screen, a method is called to remove any of the listeners that are currently active on them:
public function Deactivate():void
{
this.removeEventListener(TouchEvent.TOUCH_OUT, OnTouchOut);
this.removeEventListener(TouchEvent.TOUCH_END, OnTouchRelease);
this.removeEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin);
}
This is just for the standard button functionality (up/down texture and sound), on top of this, when I make the game, in my rollout class, I have an additional method that will add another event listener for custom logic that should occur when the button is touched (the button itself is created elsewhere).
public function AddRolloutButton(listener:Function):void
{
if (listener != null)
{
_buttons[index].addEventListener(TouchEvent.TOUCH_BEGIN, listener);
}
The buttons in the rollout itself are removed from the display list until they are to be shown. When the rollout is closed, the buttons are deactivated (removed from display list and the 3 button listeners within the button class are removed).
Everything works perfectly fine the very first time I open and close the rollout. After that, the event dispatching system just inexplicably dies. Every single InteractiveObject on the screen, regardless of position or type, becomes unusable. I traced out whether or not the listeners were still there on the rollout toggle button, and it was. I also confirmed that the rollout button itself was the only thing on the display list.
What I've noticed is that if I comment out the listener removal in the deactivate method of the button for the touch begin listener, or pass in null for the listener method in the AddRolloutButton method, everything works just fine. The issue seems to stem from having multiple listeners of the same type on the rollout buttons, and then removing one or all of them.
If anyone has any ideas of just what is going on, that would be very helpful. I was under the impression that adding multiple listeners of the same type to an InteractiveObject was perfectly valid.
UPDATE:
It appears that only TouchEvents get broken by this issue I'm having. I just tried using a mouse click listener on the stage after opening and closing the rollout, and that still works. So, only touch events are getting broken, if that helps at all.
Seems like there is something going wrong in your AddRolloutButton method. Are you sure you are assigning the correct listener function?
In your example the listener:Function argument should be equal to _buttons[index]. OnTouchBegin.
Or, since whatever class that owns the AddRolloutButton method seems to be in control of the buttons, you could potentially scrap the listener argument altogether since you know what method that needs to be triggered.
For example like this:
public function AddRolloutButton():void {
var currentButton:MyButtonClass = _buttons[index] as MyButtonClass;
currentButton.addEventListener(TouchEvent.TOUCH_BEGIN, currentButton.OnTouchBegin);
[...]
}
However, what you could do is to never remove the TouchEvent.TOUCH_BEGIN in the Deactivate function. The touch events will never be triggered when the DisplayObject isn't on the Display List. This means you don't have to worry about adding the listener every time you want to add the button to the Display List again.
If you set the listener to use a weak reference it will not hinder the button from being garbage collected when it's not needed anymore. To make your event listener use a weak reference, set the fifth argument of the addEventListener method to true.
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
public function Initialize():void {
this.addEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin, false, int.MAX_VALUE, true);
}
Do you call the Initialize method again at some point after closing the rollout?
From your code it looks as though you remove all of the event listeners in Deactivate and then never add the TouchEvent.TOUCH_BEGIN listener again.
I'm not sure what you're trying to accomplish by removing the event listeners. Since the Button has a reference to the callback, it has a reference to that callback whether the listeners are attached or not. Are you thinking that adding a listener creates a reference from the callback to the button? It doesn't--the reverse is true.
If you really want to have the Button release the callback when it is removed from the display list, then it can't hold that reference after it removes the listeners. Consider using something like Supervising Presenter or a RobotLegs Mediator to manage those dependencies.
I seriously doubt that the entire event system is being borked by what you're doing.
I'd be more inclined to believe that this:
if (listener != null)
{
_buttons[index].addEventListener(TouchEvent.TOUCH_BEGIN, listener);
}
is failing, either because the button that's referenced is not the one that's actually on stage, or because listener is null..
I have seen times where adding and removing events with priorities can cause things to fail, but typically this is with events that aren't propagating on the display list.
One way that you can test this is simply to listen to the main document or the stage for touch events and see if you're getting those events. If the entire event system is borked, you won't get them, but if your listener logic is wrong, you will.
You may also want to check the willTrigger property on the button and event.

Event once all the custom item renderers have been created/set

I'm using a custom item renderer in my datagrid, and need to make a button visible or invisible based on if there has been a negative value on any of the values in the renderer. So I'd like to set a flag to false when the first renderer is set off, turn it to true if there's any negative values, and at the end check for the value of the flag. I know I can dispatch a dataChange event for every time the data is changed in the renderer instances, but I was wondering if there is anyway I can know when all of them are done?
Thanks!
There is no such event.
Like any other Flex component, a renderer will dispatch a CREATION_COMPLETE after it's been created. ItemRenderers are generally recycled (the same object gets assigned new data to render), thus listening for CREATION_COMPLETE is not sufficient, unless you disable the recycling.
For a Spark List component, you can disable recycling by setting useVirtualLayout=false on the layout class. I'm not sure if the Spark DataGrid class support this or not. The MX DataGrid may have some other way to do this.
Disabling the recycling, however, can have performance implications. I think your idea w/the DATA_CHANGE event is the best solution:
determine the initial state of the data (ie: are there any negative values)
in the renderer, use the DATA_CHANGE event (or just override the setter for the renderer's data property) to know when the data has changed
When the data changes, dispatch a custom event class that will bubble. This event has a property that tells you if the value is negative or not.
Since your custom event from the renderers will bubble up to the grid, you can add one listener on the grid to handle changes from all the renderers.
You should have a look into RendererExistenceEvents. You should be able to tell when they are all created based on how many items you have in your list or at least how many should be in view at once.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/events/RendererExistenceEvent.html

Bindable function without event name specified

What is the effect of making a function Bindable in flex without specifying event name with it? I have done this in my code and it seems to be working alright without any associated event (however it does generate a warning). If I remove the binding from such functions it will does effect the code and doesnt reflect the changes if the return value from the function changes.
Could someone explain me , how and why such Bindable function work even without any event associated with [Bindable] tag.
Example:
<mx:Image id="a" source="{getImage(1)}" useHandCursor="true" buttonMode="true" width="10" height="10" click="finalize(event)" autoLoad="true"/>
[Bindable] private var _ratingSelected:int;
[Bindable]
private function getImage(value:int):String
{
if (value <= _ratingSelected)
return 'images/hr/applicants/star_icon.png';
else
return 'images/hr/applicants/star_icon_dis.png';
}
If I remove the Bindable tag from getImage function here, the image doesnt properly get updated at the run time. Please note that _ratingSelected is Bindable variable here. Even though I don't have any event associated with getImage() function, making it Bindable seems to be working just alright. Does it automatically detect changes to changes in _ratingSelected variable (which is bindable) and call the getImage function at run time? Kindly enlighten.
Thanks.
When you don't specify an event name in the Binding tag, it uses the event "propertyChange". This means that every time the framework gets a "propertyChange" event from your document, it'll try to update the image source by calling getImage again.
Now when the value of _ratingSelected is updated, a "propertyChange" event is dispatched internally, which then causes the image to be updated.
Note that this has nothing to do with whether getImage actually uses _ratingSelected to generate its return value. The only connection between getImage and _ratingSelected from the data binding framework's point of view is the "propertyChange" event which they both claim to dispatch when their respective values have changed (even though getImage never actually dispatches it).

MVC Pattern - Bind event listeners from controller onto views elements?

How do you bind an event listener from the controller to the view's elements eg button (click event) to its own handler?
Originally I was doing this from the view eg.
button.addEventListener(MouseEvent.CLICK, controller.buttonClick);
But now realise this is wrong since reading "each view is only supposed to "know" about the model which it represents, and "know" nothing of the controller"
model should have instance of this button, so controller will access model to add event listener, but view will only show this button, only add to stage.
Controller has direct reference to the view so can bind event listeners to the appropriate view elements. View can expose public methods to set bindings if you like.