From Flash to Flex: Understanding Flex Events
Everything in Flex occurs based on an event. This means that simply clicking a button or key to moving the mouse or receiving a response from a web service provides developers with the ability to trigger a custom event in their Flex applications. That’s a lot of control, and since Flex is not based on the request/response model of a standard web app, the app contains the functionality to perform those custom events without ever leaving the web page. This is because events are client-based—in other words, separated from the request/response model of a web page and do not require the page to refresh with every user interaction.
On the Web a Flex app is completely loaded upfront, which allows the functionality within to respond faster than a standard web request model. This will initially cause the user to wait until the app is fully loaded, but will save time when it counts, which is during usage.
Not having to wait for a page refresh also prevents the user from having problems maintaining context because the screen reacts instantaneously. With these additional benefits you would expect some new issues to arise, but the capabilities of Flex are not limited in any way when comparing them with a standard web app.
In this article you will learn how to leverage the power of events by dispatching them in your own custom classes. The source code for this project can be downloaded here.
If you feel you need some background on Flex development before diving into events, take a look at the previous articles in the From Flash to Flex series.
Event Dispatching
Dispatching your own events starts by extending the UIComponent. In the last article of the Flash to Flex series, "Creating ActionScript Components for Flex," I explained how to create a Flex component by extending the UIComponent.
This article will pick up where that article left off by adding the additional functionality to dispatch your own custom events when a headline is selected. As a quick recap, the headline component that we built ran from XML, which defined a URL and display text for different headlines. When the app loaded, the component would cycle through each of the headlines for a predetermined interval that we passed to the constructor. Each headline would display at the top of the page waiting for someone to click it and visit the corresponding URL.
Since the UIComponent extends the EventDispatcher, all subclasses of the UIComponent have access to the dispatchEvent() method.
Relying on the href to link us to the URL of a headline works great, but if we wanted to add some additional functionality each time a headline is selected, such as logging what headlines were selected and at what time, this functionality would not allow it.
Therefore we will use events to inform a custom handler of the selection and then we will dispatch an event and delegate it to the appropriate class, which will log the data that we define.
First of all, we need to change the way that our headlines are constructed to trigger an event in the href (see Listing 1) instead of just linking to the URL as we did before (see Listing 2).
Listing 1: Triggering an event
this.headlines.push("<a href=’event:"+ _headlines[i].attribute("action") +"’>"+ _headlines[i].text() +"</a>");
Listing 2: Simply linking to the URL
this.headlines.push(’<a href="’+ _headlines[i].attribute("action") +’" target="_blank">’+ _headlines[i].text() +’</a>’);
If you have developed with Flash, the first thing that you’ll probably notice in Listing 1 is that we are not using asfunction any more; there is now a way to trigger an event from an href.
Now that we have our event in place we need to add a listener to the textfield that we are creating to display the headlines.
To do this I have added the event listener to the createTextField method from our previous headline class and modified it a bit to handle the text directly as a parameter rather than assigning it after the field has been created (see Listing 3).
Listing 3: Adding an event listener
private function cycle(index:Number):void { if(this.currentTextField != null) removeChild(this.currentTextField); this.currentTextField = this.createTextField(0, 0, 200, 100, this.headlines[index]); if(index == (this.headlines.length-1)) index = 0; else index++; if(this.__cycleTimeout != 0) clearTimeout(this.__cycleTimeout); this.__cycleTimeout = setTimeout(cycle, (this.delay*1000), index); } private function createTextField(x:Number, y:Number, width:Number, height:Number, text:String):TextField { var format:TextFormat = new TextFormat(); format.font = "Arial"; format.color = 0x333333; format.size = 21; format.underline = true; var txtField:TextField = new TextField(); txtField.x = x; txtField.y = y; txtField.width = width; txtField.height = height; txtField.autoSize = "left"; txtField.defaultTextFormat = format; txtField.htmlText = text; txtField.addEventListener(TextEvent.LINK, onHeadlineSelected); addChild(txtField); return txtField; }
In the createTextField method we added the event listener after the field has been created and assigned the value of the headline. Let’s not forget to include the appropriate class (see Listing 4).
Listing 4: Importing the TextEvent
import flash.events.TextEvent;
Now that our event is being listened to, the next step is to handle it. We will need to create an onHeadlineSelected method to correspond to the event that we defined previously (see Listing 5).
Listing 5: Handling the event
private function onHeadlineSelected(e:TextEvent):void { var u:URLRequest = new URLRequest(e.text); navigateToURL(u, "_blank"); e.currentTarget.addEventListener("textlink", Logger.GetInstance().Log); var tev:TextEvent = new TextEvent("textlink", false, false); var date:Date = new Date(); tev.text = date.toString() +"::"+ e.text; e.currentTarget.dispatchEvent(tev); }
If you are transitioning from Flash you’ll notice that there is no longer a getURL method. Instead we need to create a new URLRequest from our URL and then use it in the navigateToURL method, which allows us to target the browser window just as getURL did.
The next line assigns an event listener to a method called Log in a new class called Logger, which we will create in a moment (see Listing 6).
You’ll also notice that we are providing the listener with a custom type called textlink, which will prevent any recursion issues when our other events are fired.
Once we have the listener in place we need to create a new event, which in this case is a TextEvent, set the values that we want to pass the new method and finally dispatch the event to whomever is listening.
Now that we are finally dispatching events, let’s take a look at how to handle them from other classes.