dispatch event in Flex 4 - apache-flex

I could not get the event to dispatch. is there any thing missing in my code?
Application1.mxml:
<s:Button x="50" y="10" label="Button" click="dispatchEvent(new Event('buttonToggle'))"/>
component1.mxml
[Bindable(event="buttonToggle")]
public function disableChk():void {
trace("event");
}

It is not very clear what do you want to ask but I'll try to explain the code I see.
First, dispatching and listening events are performing by dispatchEvent() and addEventListener() of flash.events.EventDispatcher. So you're dispatching event right. But what about listening? To listen to event you should add something like (in the same MXML class where event is dispatching):
addEventListener("buttonToggle", onButtonToggle);
…
private function onButtonToggle(event:Event):void
{
trace("event");
}
What about your example it is not about event handling but about data binding. And of course data binding relies on event dispatching/handling under the hood but there are some limitations to check if event dispatching works using data binding.
First of all, you're using function as a source of data binding. And there are to problems with it:
Using bindable function without returning value (you have void) is non-sense.
Even if your function will return value it won't call if there is no any bindings in MXML attributes to this function.
But to solve problem of your code (but not your question) we need to have more information about your goal and more code about your implementation.
For the simplest way of handling events of MXML components within the same component you can use very simple handlers:
<s:Button x="50" y="10" label="Button" click="myClickHandler()"/>
and:
private function myClickHandler():void
{
trace("Event");
}
You can read more about handling events from the official documentation.

Related

Drag and Drop - How to get the DragSource on the DragStart event

When I start a drag operation I would like to be able to highlight the possible valid Drop objects. For this I need to know when the drag operation starts and which items are being dragged. I am trying to do this using the dragStart, but the event.dragSource is null on this event.
I have this list:
<s:List
width="100%"
height="100%"
id="productsListing"
dragEnabled="true"
dataProvider="{products}"
dragStart="dragStartHandler(event);"
dragComplete="dragCompleteHandler(event);"
itemRenderer="views.productListed" />
And I have the listener as:
public function dragStartHandler(event:DragEvent):void {
var itemsVector:Vector.<Object> = event.dragSource.dataForFormat('itemsByIndex') as Vector.<Object>;
//Verify Items
//Highlight appropriated dropZones
}
Anyone have a good sugestion how to overcome this?
The problem here is that your dragStartHandler is taking higher precedence than the List components internal dragStartHandler - which is where the drag operation is started and the dragSource property created.
Suggestion, manually add your dragStartHandler with a lower precedence than the List components dragStartHandler method - looking at the code this needs to be less than -50.
MXML Code:
<s:List width="100%" height="100%"
id="productsListing"
dragEnabled="true"
dataProvider="{products}"
initialize="productsListing_initializeHandler(event)"
dragComplete="productsListing_dragCompleteHandler(event)"
itemRenderer="views.productListed"
/>
AS Code:
protected function productsListing_initializeHandler(event:FlexEvent):void
{
// Needs to be handled AFTER the List component has handled the event and attached the dragSource data, hence priority is -51
this.productsListing.addEventListener(DragEvent.DRAG_START, productsListing_dragStartHandler, false, -51, true);
}
protected function productsListing_dragStartHandler(event:DragEvent):void
{
// Your code here...
}
I hope you find that useful.
This is the in built solution for drag drop in flex
we can implement the Object Handles for all component
it is easy to drag, drop and resize.
refer this http://code.google.com/p/flex-object-handles/

Flex: Programmatic equivalent of tag-based event handlers?

When I create something like the following:
<mx:DataGrid id"myDataGrid"
itemEditBegin="myDataGrid_itemEditBeginHandler(event)" />
When does the event listener for "itemEditBegin" get added and removed? Is this essentially the same as:
<mx:DataGrid id="myDataGrid"
creationComplete="myDataGrid_creationCompleteHandler(event)" />
protected function myDataGrid_creationCompleteHandler(event:FlexEvent):void
{
this.myDataGrid.addEventListener(DataGridEvent.ITEM_EDIT_BEGIN,
this.myDataGrid_itemEditBeginHandler);
}
protected function myDataGrid_whatEventDispatcherGoesHere?Handler(event:FlexEvent):void
{
this.myDataGrid.removeEventListener(DataGridEvent.ITEM_EDIT_BEGIN,
this.myDataGrid_itemEditBeginHandler);
}
Basically, I'm wondering where I should add "myDataGrid.addEventListener" if I want to do it programmatically? Should it be in the creationComplete listener function of the object itself, or perhaps in the creationComplete listener function for whatever parent object it resides in?
If you're adding the event listener programmatically:
creationComplete handler of the object is a good place for it
If you're creating the dataGrid programmatically, just add it anytime after instantiating the object
Putting it the in the Parent's creationComplete handler adds unnecessary complexity to your code, and I wouldn't recommend it. However, it will work.
Good reference for object creation in Flex: http://www.mikaflex.com/?p=270

detect change in Flex Form elements (textinput, textarea, combobox, checkbox..)

I have various (read lots of..) flex forms in my app, and I now want to create a system by which the user is notified that he hasn't saved if he modifies anything in the form...
now.. I don't want to rewrite every form I have.. is there some nice way to implement this?
Extending the TextInput (and others..) classes somehow?
thanks
This is not really thought through but should work.
You could create a custom component, let's call it FormWatcher which you would than put next to your Form. What the form watcher would do is wait for the CreationComplete event from the form.
So now, as we have the Form ready you can use the getChildren() method of the form to get all the FormItems in it. Than look inside each of them, and you will get TextInputs, Comboboxes, etc. to which you can add event listeners (as individual components), eg.
// THIS IS WHERE THE COMPONENT SHOULD START
protected function changeHandler(event:Event):void
{
trace ("something is dirty");
}
protected function startWatching(passTheFormHere:Form):void
{
for each (var O:Object in passTheFormHere.getChildren())
{
if (O is FormItem)
{
// Let's assume you only have a single child in one FormItem
// and always one child for simplicity
addChangeHandlerFor((O as FormItem).getChildAt(0));
}
}
}
protected function addChangeHandlerFor(someComponent:Object):void
{
// Most regular flex components send a Event.CHANGE event
// when their value is changing
// keep in mind you should check stuff, this is a simple example
(someComponent).addEventListener(Event.CHANGE,changeHandler);
}
// THIS IS WHERE THE COMPONENT SHOULD END
Just paste this code next to some form, and call the startWatching(nameOfYourForm), you should see the changeHandler is being called.
A few more notes:
1) You should clean up the event listeners once you're done.
2) I would create a component out of it so that you would use it like this:
<mx:Form id="form1" >
[...]
</mx:Form>
<FormWatcher form="{form1}" />
Where FormWatcher would have a Boolean var called "clean" or something.
3) The example is very simple, so it will only work for forms similiar to this one:
<mx:Form id="myForm" >
<mx:FormItem>
<mx:TextInput id="someComponent1" />
</mx:FormItem>
<mx:FormItem>
<mx:CheckBox id="someComponent2" />
</mx:FormItem>
<mx:FormItem>
<mx:TextArea id="someComponent3" />
</mx:FormItem>
</mx:Form>
You could go into the TextInput class (and others) and add that event listener and function, but then you would be changing the SDK itself, which is kind of a bad idea. I would create custom classes extending the ones your using and do a find/replace to make it faster.

In Flex, is there something like a 'this' reference for an MXML component?

I could code what I want to achieve like this:
<mx:Button id="someButton" click="doRememberButton(someButton)" ... />
but would find it very helpful (I am putting together a rather large UI) if I could write:
<mx:Button click="doRememberButton(this)" ... />
Now, the obvious problem is that 'this' does not point to the Button, but to the main component defined by the file the code is in (e.g. VBox), yet it would be a great help if I had some reference to the 'current' MXML component..
Would anybody have a solution for this? Thanks!
Tom
Inline event handlers is really just wrapped code, so you may use the event object to get details of the dispatcher and other event information. Like so:
<mx:Button click="trace(event.target)" />
In your case, you'd have to change the signature of your event handler, e.g.:
private function doRememberButton(event:Event):void
{
...
}
And in the MXML code:
<mx:Button click="doRememberButton(event)" />
The target property of the event class is the original dispatcher of the event. There is also a currentTarget property which is the current target in the event chain. This relates to event bubbling. There is more information on this in Adobe LiveDocs
private function doRememberButton(ev: Event) {
//this gives your button
ev.currentTarget;
}
here is a solution more precisely the way u needed
<mx:Button id="someButton" click="doRememberButton(event.currentTarget as Button)" />
at the function:
private function doRememberButton(thisBtn:Button):void
{
...
}
that's it! :)

Problem with dispatching custom event in FLEX

Let me start off by saying that I'm pretty new to flex and action script. Anyways, I'm trying to create a custom event to take a selected employee and populate a form. The event is being dispatched (the dispatchEvent(event) is returning true) but the breakpoints set inside of the handler are never being hit.
Here is some snippets of my code (Logically Arranged for better understanding):
Employee Form Custom Component
<mx:Metadata>
[Event(name="selectEmployeeEvent", type="events.EmployeeEvent")]
<mx:Metadata>
<mx:Script>
[Bindable]
public var selectedEmployee:Employee;
</mx:Script>
...Form Fields
Application
<mx:DataGrid id="grdEmployees" width="160" height="268"
itemClick="EmployeeClicked(event);">
<custom:EmployeeForm
selectEmployeeEvent="SelectEmployeeEventHandler(event)"
selectedEmployee="{selectedEmployee}" />
<mx:Script>
[Bindable]
private var selectedEmployee:Employee;
private function EmployeeClicked(event:ListEvent):void
{
var employeeData:Employee;
employeeData = event.itemRenderer.data as Employee;
var employeeEventObject:EmployeeEvent =
new EmployeeEvent( "selectEmployeeEvent", employeeData);
var test:Boolean = dispatchEvent(employeeEventObject);
//test == true in debugger
}
private function SelectEmployeeEventHandler(event:EmployeeEvent):void
{
selectedEmployee = event.Employee; //This event never fires
}
</mx:Script>
There are a few things conspiring to cause trouble here. :)
First, this declaration in your custom component:
<mx:Metadata>
[Event(name="selectEmployeeEvent", type="events.EmployeeEvent")]
<mx:Metadata>
... announces to the compiler that your custom component dispatches this particular event, but you're actually dispatching it with your containing document, rather than your custom component -- so your event listener never gets called, because there's nothing set up to call it.
Another thing is that, in list-item-selection situations like this one, the more typical behavior is to extract the object from the selectedItem property of the currentTarget of the ListEvent (i.e., your grid -- and currentTarget rather than target, because of the way event bubbling works). In your case, the selectedItem property of the grid should contain an Employee object (assuming your grid's dataProvider is an ArrayCollection of Employee objects), so you'd reference it directly this way:
private function employeeClicked(event:ListEvent):void
{
var employee:Employee = event.currentTarget.selectedItem as Employee;
dispatchEvent(new EmployeeEvent("selectEmployeeEvent"), employee);
}
Using the itemRenderer as a source of data is sort of notoriously unreliable, since item renderers are visual elements that get reused by the framework in ways you can't always predict. It's much safer, instead, to pull the item from the event directly as I've demonstrated above -- in which case you wouldn't need an "employeeData" object at all, since you'd already have the Employee object.
Perhaps, though, it might be better to suggest an approach that's more in line with the way the framework operates -- one in which no event dispatching is necessary because of the data-binding features you get out-of-the-box with the framework. For example, in your containing document:
<mx:Script>
<![CDATA[
import mx.events.ListEvent;
[Bindable]
private var selectedEmployee:Employee;
private function dgEmployees_itemClick(event:ListEvent):void
{
selectedEmployee = event.currentTarget.selectedItem as Employee;
}
]]>
</mx:Script>
<mx:DataGrid id="dgEmployees" dataProvider="{someArrayCollectionOfEmployees}" itemClick="dgEmployees_itemClick(event)" />
<custom:EmployeeForm selectedEmployee="{selectedEmployee}" />
... you'd define a selectedEmployee member, marked as Bindable, which you set in the DataGrid's itemClick handler. That way, the binding expression you've specified on the EmployeeForm will make sure the form always has a reference to the selected employee. Then, in the form itself:
<mx:Script>
<![CDATA[
[Bindable]
[Inspectable]
public var selectedEmployee:Employee;
]]>
</mx:Script>
<mx:Form>
<mx:FormItem label="Name">
<mx:TextInput text="{selectedEmployee.name}" />
</mx:FormItem>
</mx:Form>
... you simply accept the selected employee (which is marked bindable again, to ensure the form fields always have the most recent information about that selected employee).
Does this make sense? I might be oversimplifying given that I've no familiarity with the requirements of your application, but it's such a common scenario that I figured I'd throw an alternative out there just for illustration, to give you a better understanding of the conventional way of handling it.
If for some reason you do need to dispatch a custom event, though, in addition to simply setting the selected item -- e.g., if there are other components listening for that event -- then the dispatchEvent call you've specified should be fine, so long as you understand it's the containing document that's dispatching the event, so anyone wishing to be notified of it would need to attach a specific listener to that document:
yourContainingDoc.addEventListener("selectEmployeeEvent", yourOtherComponentsSelectionHandler);
Hope it helps -- feel free to post comments and I'll keep an eye out.
You're dispatching the event from the class in the lower code sample (DataGrid, I guess), but the event is defined in the EmployeeForm class, and the event handler is likewise attached to the EmployeeForm instance. To the best of my knowledge, events propagate up in the hierarchy, not down, so when you fire the event from the form's parent, it will never trigger handlers in the form itself. Either fire the event from the form or attach the event handler to the parent component.

Resources