5.8.09

AS3: How to Create a Cancelable Event

How to Create a Cancelable Event

Explanation:
The easiest way to explain a cancelable event is by example. Hopefully the following movie loads. In case it doesn't, following is a description:

  • There is a TextField which displays "Points Available: 5". The 5 represents an int in code that keeps track of the points available.
  • There are two Spinners (Spinners spinners are a text field that displays a number, and a right and left arrow button to increase or decrease the number displayed). Both Spinners start with the value "0". The available points can be distributed to the Spinners.

These two behaviors are achieved using cancelable events:

  1. When a Spinner is at 0 it can no longer be decreased.
  2. When there are 0 points available the Spinners can no longer increase.




Creating the Spinner:

Creating a cancelable event begins in the class which dispatches the event. In this case that is the Spinner class with its "SCROLL_RIGHT" and "SCROLL_LEFT" events. In this code _btnLeft and _btnRight are Buttons with their position relating to Left and Right. I won't run through the code for laying out the buttons and textfield, but if you don't know how to do it, you can download the full source at the end of this tutorial and read comments. This code goes in the Spinner class:

    private function addEventListeners():void
{
// Event called when left button is clicked
_btnLeft.addEventListener(MouseEvent.CLICK, startLeftScroll);
// Event called when right button is clicked
_btnRight.addEventListener(MouseEvent.CLICK, startRightScroll);
}pre>


addEventListeners() is called once, at the creation of the Spinner class. It sets up event listeners for when the Left and Right Buttons are clicked. These clicks will cause the Spinner class to dispatch SCROLL events, as shown in the following code:
private function startRightScroll(e:Event):void
{
// Add a listener for the dispatched event to allow cancel
// behavior.
addEventListener("SCROLL_RIGHT", endRightScroll);

// Dispatch the event
dispatchEvent(new Event("SCROLL_RIGHT", false, true));
}

private function startLeftScroll(e:Event):void
{
// Add a listener for the dispatched event to allow cancel
// behavior.
addEventListener("SCROLL_LEFT", endLeftScroll);

// Dispatch the event
dispatchEvent(new Event("SCROLL_LEFT", false, true));
}


In the previous code, an event listener is added for the event that is about to be dispatched. It is important to do things in this order so that the Spinner class is the last object to be notified about a SCROLL event, giving the other classes a chance to mark the event as cancelled. It is also important to note that when dispatching the events, the "cancelable" parameter is set to "true". Finally the code that actually controls if the behavior occurs or not is contained in the endLeftScroll() and endRightScroll() methods.
public function endRightScroll(e:Event):void
{
// Remove the event listener
removeEventListener("SCROLL_RIGHT", endRightScroll);

// If the default behavior hasn't been cancelled
if (e.isDefaultPrevented()==false)
{
// Increase the value and refresh the textbox
_value += 1;
updateValue();
}
}

private function endLeftScroll(e:Event):void
{
// If the default behavior hasn't been cancelled
if (e.isDefaultPrevented()==false)
{
// Decrease the value and refresh the textbox
_value -= 1;
updateValue();
}
}



In these methods, A call is first made to removeEventListener(). As previously mentioned, this is done because you want to add a new event listener each time the event is dispatched, so that the Spinner object will always be the last object to get notified of the SCROLL event. The next thing to check is e.isDefaultPrevented(). If the event has been canceled, that means another class has called e.preventDefault(), which will mark isDefaultPrevented() as "true". So if isDefaultPrevented() == false, then you complete the default behavior of the event. In this case, the response to the behavior being cancelled is to just exit the method without making any changes.

Canceling the Event:

The spinner class has now been created in a way which will allow the SCROLL_RIGHT and SCROLL_LEFT events to be cancelled, all that remains is to create the code which cancels them when necessary. In the Main class _spinner1 and _spinner2 are Spinner instances, and _points is the number of points available to be distributed. After creating the controls, addEventListener() is called on the Spinners as follows:

   private function addEventListeners():void
{
// Listen for left or right scrolling on spinner 1
_spinner1.addEventListener("SCROLL_RIGHT", pointAdded);
_spinner1.addEventListener("SCROLL_LEFT", pointSubtracted);

// Listen for left or right scrolling on spinner 2
_spinner2.addEventListener("SCROLL_RIGHT", pointAdded);
_spinner2.addEventListener("SCROLL_LEFT", pointSubtracted);
}


Next pointAdded and pointSubtracted are created with if conditions which determine if the SCROLL events should be cancelled:

private function pointAdded(e:Event):void
{
// If there are points availiable
if (_points > 0)
{
// Subtract a point and update the text
_points -= 1;
updateText();
}else {
// If there are no points available
// prevent the default behavior of the
// event (cancel it).
e.preventDefault();
}
}

private function pointSubtracted(e:Event):void
{
// If the spinner value is higher than 0
if (Spinner(e.target).value > 0)
{
// Make a point available and update the text
_points += 1;
updateText();
}else {
// If the spinner is at 0
// prevent the default behavior of the
// event (cancel it).
e.preventDefault();
}
}



The zipped source code to this tutorial can be found here.

If you have comments / questions / suggestions, let me know, this is my most complicated tutorial currently and I'm trying to work on making it more clear, thanks in advance for any input.