Firstly, Happy New Year! Hope your ’09 is off to a flyer!
Secondly, sorry about the rather mundane heading – couldn’t really think of what to call this post. I’ve been typing all sorts of things into Google trying to find a solution to what I’ll describe below.
I’m continuing the project I started in early December and having some very interesting battles with AS3 and the Flex framework. I’d like to document one of those battles today.
What I wanted to do was send parameters along with an event so that the event listener had access to them. Now I’m fully aware of how to do that when I’m in charge of dispatching the event, but was (and still am) at a loss as to how to add them in the following instance:
myComboBox.addEventListener(Event.CHANGE, eventListener);
This call to addEventListener occurs where the variables I want to pass get defined.
Here’s the code that I attempted to use (without luck) to get the parameters passed along with the event:
myComboBox.addEventListener(PodEvent.CHANGE, eventListener); var myEvent:PodEvent = new PodEvent(PodEvent.CHANGE); myEvent.displayTriggerValue = displayTriggerValue; myEvent.formItem = triggerDisplay; myComboBox.dispatchEvent(myEvent);
I could get the displayTriggerListener to run when the combobox changed, but the variables that I added to myEvent wouldn’t make it in there (further to that I was having type coercion difficulties, but that’s another story I think). The initial dispatchEvent was also allowing the eventListener to get the parameters, but obviously the idea is to have them passed along with every PodEvent.CHANGE event.
Now initially I got around this using closures (a new term to me). I understand the issues of using anonymous functions (ie. garbage collection issues) so searched some more for answers. I found nada.
So after a nights rest and a few more hours wrestling with it today, I’ve come up with the following solution that I’m rather chuffed about. I use a Dictionary to store a reference to the component and in turn create an object associated with that Dictionary element to store the parameters I want to pass into the eventListener function. Perhaps some code will illustrate what the hell I just typed (for me and you both 😉
myParamDictionary[myComboBox] = {param1: value1, param2: value2};
The myParamDictionary is a private var in the class so is accessible within the eventListener
private function eventListener(e:Event):void { var _local:* = myParamDictionary[e.target] // rest of the implementation here. You can access the previously set parameters by _local.param1, _local.param2... }
And to my utter delight (and surprise) it works!
The only downside is there’s no type checking on the parameters, which is what I originally wanted to use a custom event for.
If you’ve got a suggestion for my initial problem or a critique for my end solution please don’t be shy and post them!
I can’t see a LOT of reasons why you’d want to do this. But if you were going to do it – it would probably be smarter to extend combobox so you could have more control over events that were being dispatched and whatnot instead of so tightly coupling a random dictionary in a class to a combobox… Not only does this tightly couple things, but it also creates a random dictionary in memory that is just nt necessary. Also, if you are using the dictionary, make sure to set it to use weak references – or else it will hold onto that combobox in memory and it will never be garbage collected.
Eric
I dont really see why your original idea of creating a custom event didnt work, you did add a clone method to your event class right? Because if you didm surely the event would still have had the properties you assigned it.
@ Chris
Juts because a custom event is created and dispatched immediately, it doesn’t have any effect on the event that the ComboBox will despatch when its selectedIndex is changde. When this happens, an Event.CHANGE is dispatched.
If you wanted to dispatch a custom event you would have to do what Eric stated and extend ComboBox, and dispatch you own event where ever the Event.CHANGE was dispatched.
Thats said, like Eric also mentioned this isn’t a great solution, although I guess we don’t fully know the reasons behind it.
Thanks for the comments guys.
@Eric – The reason I NEED to do this is I’m generating a form element based on the currently selected item in a combobox. Now that formitem is intelligent in that it knows what combobox and the selected item of that combobox that will trigger it’s display. But this information needs to make it into the eventListener so it can determine whether the correct item is selected. Hopefully that clarifies why I need to send the parameters along with the event. Have you got any suggestions for other ways of achieving the same thing?
As for tight coupling, well the combobx is generated within the same class as the privately declared dictionary – which too me is perfectly fine. Pragmatism has to take charge at some stage, and I see nothing wrong with declaring a private variable in a class that will then be referenced by a combobox created in that same class. That’s more like logical coupling to me.
I am setting up my Dictionary with true as it’s constructor parameter.
@Chris and Tink – I did add a clone method, still no cigar. And I realised that my initial dispatch was the only thing that was carrying the parameters along to the eventListener (hence this post).
To me extending a component to pass parameters along seems like overkill in this situation. But I’m glad to know that seems to be the approach required for future issues I may run into.
@ jason
This can be done easily through an event listener just by saying
var combo:ComboBox(event.target as ComboBox);
//then
combo.selectedItem
combo.selectedIndex
etc etc….
you can even do something like this
or since event gets passed in
sorry my mxml markup wasnt shown – and I can’t edit it…you might be able to fix it
@Erid – Thanks for following up. However, what you’ve suggested doesn’t really help me in this instance (and yes, I’m fully aware of using event.target to get access to all sorts of information about the object that broadcast the event). I need to know what item to show and hide (which is totally separate from the combobox) when the combobox is set to the designated trigger item. This information isn’t passed along with the event.
I couldn’t retrieve the code posted, and I’m doing this part of the code in actionscript so MXML isn’t really relevant.
For future reference, code placed within a “code” tag should appear ok in the comments.
I am a newbie and I think that I am attempting to do the same thing. I have a parent module that needs to trigger an event (button pressed on ButtonBar). I need a component module to see the event and be able to tell which button was pressed and do something based upon which button was pressed. In my parent module, I have:
[Event(name=”navButtonClicked”, type=”mx.events.ItemClickEvent”)]
and a function:
public function navButtonsEvent():void {
dispatchEvent(new Event(“navButtonClicked”));
}
and the buttonbar:
In my component module I have (not complete, just testing):
public function navButtons(event:ItemClickEvent):void {
var whichButton:int = event.index;
switch(whichButton) {
case 0:
focusManager.setFocus(discrepancyItems[0]);
break;
case 1:
focusManager.setFocus(discrepancyItems[0]);
break;
case 2:
focusManager.setFocus(discrepancyItems[0]);
break;
case 3:
focusManager.setFocus(discrepancyItems[discrepancyCount]);
break;
}
}
What do I need to add where for the component module to see the button click?
I do not know why we need dictionary object, I was able to access public properties of the event by type casting the event.
I used clone to get my custom properties also.
import flash.events.Event;
public class AlignControlEvent extends Event
{
public var ControlName:String;
public var ControlType:String;
public static const ALIGN_CONTROL_EVENT:String = “alignControlEvent”;
public function AlignControlEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
public override function clone():Event
{
var objAlignControlEvent:AlignControlEvent;
objAlignControlEvent = new AlignControlEvent(this.type, this.bubbles, this.cancelable);
objAlignControlEvent.ControlName = this.ControlName;
objAlignControlEvent.ControlType = this.ControlType;
return objAlignControlEvent;
}
}
while dispatching
var objAlignControlEvent:AlignControlEvent = new AlignControlEvent(AlignControlEvent.ALIGN_CONTROL_EVENT);
objAlignControlEvent.ControlType = this._type;
objAlignControlEvent.ControlName = this._name;
dispatchEvent(objAlignControlEvent);
And in handling i read them as
var objA:AlignControlEvent;
objA = (e as AlignControlEvent);
Alert.show(“[align control] [name]” objA.ControlName ” [type]” objA.ControlType) ;
@madhu – I think it’s now fairly evident (after 6 months of working in Flex) that extending the combobox and the event that it broadcasts are now the way to go. The dictionary approach that I suggested did work, but was a bit hacky and probably not something that I’d use going forward.
Thanks for stopping by and adding your 2 cents.