PDA

View Full Version : Pass parameters to function with AddEventListener Flex/AS3


djeyewater
05-02-2009, 12:26 PM
I have a List where I want to trigger a function whenever any items are added/removed from the list. So I have the following to trigger my function 'saveItems' when the list's dataProvider is modified:
FiltersUsed.dataProvider.addEventListener(Collecti onEvent.COLLECTION_CHANGE, saveItems, false, 0, true);

Now I also need to pass a parameter to the 'saveItems' function, so that 'saveItems' can tell what element it is that had its dataProvider changed (in this example 'FiltersUsed').

It was suggested to me that I should use a custom event. Reading some tutorials I got this far:
public class DataProviderEvent extends CollectionEvent
{
public static const COLLECTION_CHANGE:String = "CollectionChange";
public var parent:UIComponent;
public function DataProviderEvent(element:UIComponent, type:String, bubbles:Boolean = false, cancelable:Boolean = false)
{
super(type, bubbles, cancelable);
parent = element;
}
}

private function collectionChangeHandler(event:CollectionEvent):voi d
{
try{
dispatchEvent( new dataProviderEvent(element, event) );
}
catch(e:Error)
{Alert.show(e.message);}
}

FiltersUsed.dataProvider.addEventListener(Collecti onEvent.COLLECTION_CHANGE, collectionChangeHandler, false, 0, true);
FiltersUsed.dataProvider.addEventListener(DataProv iderEvent.COLLECTION_CHANGE, saveItems, false, 0, true);

But that still has the same problem in that I can't see how to pass the parameter needed to the event triggered by the CollectionEvent.COLLECTION_CHANGE event.

Can anyone help me with this?

Thanks

Dave

Peter Cowling
05-02-2009, 03:45 PM
Hi,

The adobe documents (http://livedocs.adobe.com/flex/3/html/help.html?content=about_dataproviders_5.html) should help.

vivoices
05-02-2009, 11:13 PM
Here is the custom event class I wrote for an admin interface project:package app.System
{
import flash.events.Event;

// This class defines all the Custom Events for the Application
// including a "result" object to return the changed dataset to the event handling method

public class AdmEvent extends Event
{
// >>>>> Variable Declarations <<<<<

// Data Event Constants
public static const DATA_CHANGED:String = "dataChanged";
// . . . and many more event types . . .


// returned result object
public var result:Object;


// >>>>> Constructor <<<<<

public function AdmEvent( type:String, r:Object, bubbles:Boolean = false, cancelable:Boolean = false )
{
super( type, bubbles, cancelable );
this.result = r;
}


// >>>>> Overrides <<<<<

override public function clone( ):Event
{
return new AdmEvent( type, this.result, bubbles, cancelable );
}
}
}public function example( value:Boolean ):void
{
// some code

// preparing result object
resultObj = new Object();
resultObj.value1 = _value1;
// . . . more values as reqired . . .

// dispatching event
var changeEvent:Event = new AdmEvent( AdmEvent.DATA_CHANGED, resultObj );

// if your class extends EventDispatcher:
dispatchEvent( changeEvent );

// if your class DOES NOT extend EventDispatcher:
evDispatcher = new EventDispatcher();
evDispatcher.dispatchEvent( changeEvent );
}Maybe you can let it extend CollectionEvent and modify whatever your app needs.
Then use the result object to pass your values.
It works fine for me.

Good luck,
David

JeTSpice
05-03-2009, 07:45 PM
I'm not sure about the collection part, but i use a simple component called EventWithData. The data can be of any type, but I haven't tried passing an arrayCollection. Here is the code:

package com
{
import flash.events.Event;

public class EventWithData extends Event
{
public var data:*;

public function EventWithData(type:String, data:*,
bubbles:Boolean = false, cancelable:Boolean = false)
{
this.data=data;
super(type, bubbles, cancelable);
}

}
}

if this "data" does not accept a collection, then maybe dispatch the event with just the item instead of the whole list.

hope that helps.

djeyewater
05-03-2009, 10:19 PM
Thanks for all the examples, I think I understand how to create a custom event now.

But I still don't understand how to trigger the custom event when a CollectionEvent.COLLECTION_CHANGE event occurs, other than listening for a CollectionEvent.COLLECTION_CHANGE event and then dispatching my custom event from the CollectionEvent.COLLECTION_CHANGE event handler. But if I did that, the CollectionEvent.COLLECTION_CHANGE event handler would need to get the extra parameter to pass to the custom event, and I don't know how I'd do that other than hard coding the extra parameter value into the CollectionEvent.COLLECTION_CHANGE event handler.

Dave

wvxvw
05-03-2009, 10:37 PM
There cannot be a variable that you should access inside the event handler which is not found either in:
- handler's owner scope.
- event's dispatcher scope.
- event's scope.
All these are accessible inside the handler.
If you still cannot get the reference of the object you need inside the handler it is most probably it doesn't exist when the handler is fired, or it's existence is doubtful.

In a plain language :p There cannot be a situation when you need an extra argument to the handler, you may not need the one you have by default, but not more than one :)
And if you do still think you need an extra argument, that just means you're doing something wrong :)

@ JeTSpice:
It is always better to override Event#clone() when writing custom event. This method is used internally by many components and you usually want clone() to return a copy of your event, not just event.

djeyewater
05-04-2009, 11:52 AM
And if you do still think you need an extra argument, that just means you're doing something wrong :)

As I'm new to Flex/Actionscript, that it is quite probable.

What I want to do, is when a CollectionEvent.COLLECTION_CHANGE event occurs on a dataProvider, get the UIComponent that the dataProvider belongs to.

Any ideas?

Thanks

Dave

wvxvw
05-04-2009, 01:22 PM
What if there are many components using the same data provider, or none?

JeTSpice
05-04-2009, 02:14 PM
djeyewater, can you fire your event on the source/component that is changing the arrayCollection? i.e., if a user populates a List by drag-dropping, can you fire the event on dragDrop rather than on the collection change?

wvxvw: thanks for the tip.

djeyewater
05-04-2009, 04:04 PM
djeyewater, can you fire your event on the source/component that is changing the arrayCollection? i.e., if a user populates a List by drag-dropping, can you fire the event on dragDrop rather than on the collection change?
Sounds like that should work, I'll give it a go. Thanks!

What if there are many components using the same data provider, or none?
Do you mean if multiple components' dataProviders are all bound to the same ArrayCollection? In my case, each of my components has a seperate dataProvider, and I'll only be attaching the event to components that do have a dataProvider, so luckily I don't think I need to worry about that.

Dave

wvxvw
05-04-2009, 07:51 PM
You just may not know how many components are using the same provider. Imagine that in DataGrid the provider is used by each column and the DataGrid itself, in Tree it is used by the number of sub-components, as many as the number of nodes the tree has etc...
What you can do: extend ArrayCollection and override addEventListener / remove eventListener to keep tracking of how many listeners ware added / removed to the collection. However, I'd think this isn't a good idea either, because you shouldn't need that functionality...
Maybe... can you explain what ware you after in general? Because it seems there must be a better way to do what you're trying to do.

djeyewater
05-06-2009, 04:05 PM
Maybe... can you explain what ware you after in general? Because it seems there must be a better way to do what you're trying to do.

I'm working on a custom XMP FileInfo panel for Adobe CS4 products (http://www.adobe.com/devnet/xmp/pdfs/XMP-FileInfo-SDK-Overview.pdf).

As part of the panel I have a number of sections with 2 lists - the list on the right has a list of all possible values that can be used, and then you can copy these values to the list on the left (see attached pic)

When the left list is updated I also need to update the textbox to the left so the changes will be saved to image's metadata. The textbox will be hidden in the final version.

Using JeTSpice's suggestion it seems to be working okay now apart from that after dropping items into a list, the list will automatically scroll up and down depending on whether the mouse is above or below it, which is annoying.

Dave

wvxvw
05-06-2009, 04:25 PM
In theory, you'd only need one dataprovider and define filtering functions for each view. But given the implementation of the view, I'd say that it would be difficult for you to come up with this task... :)
So, I'd generate new dataprovider based on what item is selected and update the second view by assigning that new data provider to it.