Bugs: One good thing about them is they keep on inspiring even when you don't want to be.

Thursday, February 9, 2012

Flex Events (Part One)

This series is a basic to advanced introduction to Flex Events. I have explained that in terms of question and answers so that it is equally useful for interview purpose as well. All comments are welcomed!!

Question:
What is an event?

Answer:An
event is an object of flash.events.Event class. This is an implicitly created
object, similar to request and response objects in a JSP, which are implicitly
created by application server. Many classes extend that class and are defined
in mostly packages: spark.events.*, mx.events.* and flash.events.*. The Spark
package defines event classes that are specific to a few spark controls,
including the TextOperationEvent and VideoEvent. The MX package defines events
that are specific to Flex controls e.g. DataGridEvent, DragEvent and
ColorPickerEvent. The last package describes events that are not unique to
Flex, but are instead defined by Flash Player e.g. MouseEvent, DataEvent and
TextEvent.

Question:
What are the various phases in event propagation?

Answer: When Flash player dispatches an Event
object, that Event Object makes a roundtrip journey from the root of the
display list to the target node, checking each node for registered listeners.
The target node is the node where event occurred. The eventPhase property takes three
values: EventPhase.CAPTURING_PHASE,
EventPhase.AT_TARGET and EventPhase.BUBBLING_PHASE so the event flow is
divided into three phases: capturing phase, targeting phase and bubbling phase.

Capturing Phase: In this phase, flash
player examines each node from root to the parent of target node to see if it
has a listener registered to handle the event. If it does, FP sets the
appropriate value of Event object and then calls that listener.

Targeting Phase: This phase consists
solely of the target node. FP sets the
proper values of Event object, cheks the target node for registered event
listeners and then calls those listeners.

Bubbling Phase: This phase considers
all the nodes from parent of target node to the root node. FP sets proper value
on Event object and then calls event listeners on each of these nodes.Flash Player stops
after calling any listeners on the root node.

During each phase the nodes have a chance to
react to the event. For example consider a button inside a vbox in an
application.

If a user clicks on this button, Flex checks
the application and the Vbox for listeners during capturing phase. Flex then
triggers the Button’s listeners in target phase. In the bubbling phase, the
VBox and then the application are again given a chance to handle the event, but
now in reverse order of capturing phase. Not all events participate in all the
phases. Some events are directly
dispatched to target node and don’t participate in bubbling and capturing
phase.

In action script we can register listener on
a target node and on any other node along the flow. Some events may target
objects that are not on display list, such as events dispatched to an instance
of Socket class. These event objects flow directly to the target node, without
participating in capturing or bubbling phase. We can also cancel an event as it
flows through the event model even though it was supposed to continue to other
phases. We can do this if cancelable property is true.

Any event can be captured but no display
object listens during capturing phase unless we explicitly instruct them to do
so. Capturing
is disabled by default. The only way to add a listener during this phase is to
pass true for the use_capture when calling the addEventListener().If
we add an event listener inline with MXML, Flex sets this argument to false; you cannot
override it.

myPanel.addEventListener(MouseEvent.MOUSE_DOWN, clickHandler, true);

If we set the use_capture
argument to true the event can still bubble,
but capture phase listeners will not react to it. If you want your event to
traverse both the capturing and bubbling phases, you must call addEventListener()
twice: once with use_capture
set to true, and then again with use_capture set to false. The capturing phase is very rarely used, and it
can also be computationally intensive. By contrast, bubbling is much more
common.

An event can bubble if its bubble property is set to
true. The Object that the event is currently bubbling thorough is the currentTarget.

Question:
What are target and currentTarget properties?

Answer: For an Event object, target
refers
to the dispatcher of this event and currentTarget refers to the current
node that is being examined. When we handle a mouse event (say click) on a
button then the event.target may be the subcomponent UITextField that defines the
label, is user click on the label. So Button is the object listening to the
event, but it’s the UITextField that dispatched the event. During the targeting phase the value of
both are same.

Here, all children of panel inherit the same
listener. As Flex invokes the handler on bubbled event, we use target rather than the currentTarget property.

Question:
Which function is responsible for setting the target property of an event?

Answer:
dispatchEvent()

Question:
What are the bubble and cancellable property of an event?

Answer:Both
are Boolean properties. The first property specified whether event can bubble
or not and later specifies whether event can be cancelled or not. If it can be
cancelled then we can use preventDefault() method.

Question:
What is an event listener/handler?

Answer: An event listener is the function that
handles the event. This needs to be registered to display list using
addEventListener() method in action script, or it can also be called in mxml.
For example:

But it
is best practice to use addEventListener method, because:

This
method gives more control over event by letting us configure priority,
capture settings and use event constants.

Also
if an event is added using this method, it can be removed using removeEventListener() method.

If we
need to work with the Event object it need to be passed in mxml tag using Event keyword, but it is
not necessary to pass it in mxml. But in action script if we don’t specify an
argument in event handler, event is passed anyway and we will get a runtime
error. An event listener can be registered with an object only if it dispatches
that kind of event.
For example a Form containing a button cannot dispatch an
event of type click, as click events are
not dispatched by a Form.

Question:
How to dispatch an event in Flex?

Answer:An
Event object needs to be created before dispatching it.

Event(event_type:String, bubbles:Boolean, cancelable:Boolean)

The method dispatchEvent() is used to dispatch the event. This
method is inherited from EventDispatcher class, which is
extended by UIComponent class. So all
components which extend UIComponent class can dispatch
an event.

componentInstance.addEventListener( event_type:String, event_listener:Function, use_capture:Boolean, priority:int, weakRef:Boolean)event_type– Type of event, can be a String or a static constant such as MouseEvent.CLICKevent_listener – The event handler function.use_capture– This controls the phase in event flow when the listener will be active. If its true the listener is active during capture phase, else in targeting and bubbling phase.priority– higher the value, sooner the listener will be executed.Default value is zero but cane be set to negative/positive integer value.weakRef- A Strong reference prevents the listener from being garbage collected and a weak does not.

If an object registers a listener for an event, it
assigns a reference to it in internal array known as a listener list and
maintains that reference until the listener is unregistered explicitly via the removeEventListener() method.

Here the anonymous function is permanently stranded
in the Stage instance’s listener list. The program cannot unregister the
anonymous function because it has no reference to that function. Stranded
listeners are a big problem and cause memory waste and other side effects in
AS.

Question:
What exactly is the importance of weakRef parameter in addEventListener()?

Answer:
We know that when an object registers a listener for
an event it needs to be explicitly unregistered. If we set a listener with useWeakReference set to true it
prevents that listener from becoming stranded in the listener list of the
object with which it registered. For example suppose an Object obj registers a listener list
for an event evt. Also suppose that the only reference the program has
to list is the one held by obj. Normally list would be held by obj
until list is unregistered for the event evt. However as list was
originally registered with useWeakReference set to true, and because obj holds the only remaining reference
to list in the program, list becomes eligible for garbage
collection. So GC can choose to remove list from obj’s listener
list and delete it from memory.

Now can we say we can set useWeakReference to true for all
the listeners and need not to remove them manually? Well answer is NO. We don’t
know when will GC be called and also our application may not use enough memory
to trigger a garbage collection. As a result, the listener will continue to be
executed anytime that particular event is dispatched. So it should not be
relied on as a way to automatically remove event listeners.

Question:
Can we pass additional parameters to event handler while using
addEventListener()?

Answer:
We can pass additional parameters depending upon how
we add the listeners. If we define our listener using addEventListener() we
cannot arbitrarily add new parameters, so the following is wrong:

public function addListeners():void {

b1.addEventListener(MouseEvent.CLICK,clickListener);

}

public function
clickListener(e:MouseEvent, a:String):void {

...

}

But we can define a pass-through method like:

private var specialParam1:String;

private var specialParam2:String = "42";

private function initApp(e:Event):void {

assignSpecialParam(e);

/* Change the value of specialParam whenever the user changes it in

the TextInput and clicks the button. */

ti1.addEventListener("focusOut", assignSpecialParam);

/* Define the pass-through method in the addEventListener() method

call. You can add any number of parameters, as long as teh target

method's signature agrees. */

myButton.addEventListener(MouseEvent.CLICK,function(e:

MouseEvent):void
{ myClickListener(e, specialParam1,

specialParam2); } );

}

private function assignSpecialParam(e:Event):void {

specialParam1 = ti1.text;

}

/*
This method acts as the event listener, and it has any number of

parameters that we defined in the addEventListener() call. */

private function myClickListener(e:MouseEvent, s1:String,

s2:String): void {

myButton.label = s1 + "
" + s2; } ]]>

Question:
What is the signature of removeEventListener() function?

Answer:

componentInstance.removeEventListener(event_type:String,

listener_function:Function, use_capture:Boolean)

We can listen for events during all event phases by
callign addEventListener() twice: once
with use_capture to true and then again with false. To remove both
we call removeEventListener() twice with
with use_capture set to true and false. We can only remove the event handlers added with
addEventListener() method in ActionScript code. We cannot remove event handler
that was defined in MXML tag.