Fingers tutorial

by Filip Zawada

Intro

I found dealing with listeners really annoying, especially during simple, repetitive tasks in Flash CS tool (mainly, due to lack of code generation). That inspired me to think about convenient solution, and later on, code it.

I wanted to use best, known to me techniques. As a result, Fingers are extensively TDD'ed with ASUnit & Hamcrest, they are crafted with huge help of IntelliJ Idea, and finally they use cool, out of the box solutions.

Fingers are designed to be tiny (2KB), that's why I like to say about them as about micro AS3 extension. Their only job is to simplify AS3 event management, make your code shorter and more readable. Technically speaking Fingers are a wrapper for any IEventDispatcher.

Examples

As an example, let's take a look at the following code:

Pure AS3 code:

obj.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
    nextFrame();
})

Fingers equivalent:

on(btn).click += nextFrame;

What we've done is added listener to a button, so after clicking a button,nextFrame() method is called.


Another example in pure AS3 - preloading:

loaderInfo.addEventListener(ProgressEvent.PROGRESS, loaderInfo_progressHandler);
loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler);

Fingers version:

on(loaderInfo).progress += loaderInfo_progressHandler;
on(loaderInfo).complete += loaderInfo_completeHandler;

If we want to clean after ourselves, we typically type:

loaderInfo.removeEventListener(loaderInfo_progressHandler);
loaderInfo.removeEventListener(loaderInfo_completeHandler);

Fingers alternative:

on(loaderInfo).removeAllListeners();

or...

on(loaderInfo).progress -= loaderInfo_progressHandler;
on(loaderInfo).complete -= loaderInfo_completeHandler;

Enough? Install Fingers from swc or download source code. Don't forget to read the rest of this tutorial.

Huh? nextFrame is a Function, nor the Number or String?

Yes, it's the MovieClip.nextFrame method. To make Fingers most effective, +/- operators were overrided. As a result of that you can:

// set/override listeners:
on(btn).click = nextFrame ;

// add listeners:
on(btn).click += nextFrame  +  btn_clickHandler;

// remove listeners:
on(btn).click -= nextFrame  +  btn_clickHandler;
Please note, that you don't have to import on function, it's global (for convenience reasons).

What if I'd like to use Fingers with my custom class?

You can use fingers with any IEventDispatcher you wish, this code will work for you:
on(yourClassInstance).yourEvent += yourListener;

Is that all?

No, you've just seen the most important part of Fingers, but that's definitely not all. You can explore following topics, to learn Fingers completely:
  1. on() statement

    Using on

    Think about on() function as an AS3 keyword. You can code more in a way you speak, i.e. "on button click, call my function" translates into:
    // on button click call my function
    //  ↓   ↓      ↓            ↓
       on( btn ).click  +=  myFunction;
    
    so, the general syntax is following
    on(o:IEventDispatcher).<eventType> <operator: =, +=, -=> <yourFunctions> 
    

    where:

    • o is an object - event dispatcher, to which we will add/remove listeners
    • <eventType> - a type of an event, on which operations are performed (it can be any type you wish). In this case, "click" was used, coming from MouseEvent.CLICK = "click"
    • operator:
      • used for setting listeners (removes existing ones)
      • += used for adding listeners (keeps existing ones)
      • -= removes specified listeners
    • <yourFunctions> - listeners you wish to add. Combining listeners together is allowed, e.g:
      on(btn).click += listener1 + listener2;

    Beware to finish on statement with a proper method call (see more).

    Please note, that every time I use one of these terms: "on() listeners", "listeners ... through on() syntax", I'm talking about listeners which were added/removed through on() statement (in contrast to these ones added through native addEventListener/removeEventListener/...).

  2. Short listeners

    Short listeners

    Fingers allows you to use typical listeners with event:Event argument:
    function typicalListener(e:Event):void {
    	trace(e);
    }
    and the short ones
    // so these without arguments
    function shortOne1():void {
    	// body
    }
    
    // or with unlimited number of optional arguments
    function shortOne2(p:Object = null, p2:Object = null):void {
    	// body
    }

    It's up to you, which one will you use.

  3. Setting listeners

    Setting listeners

    By setting listener(s), you remove all the previous listeners added through on(). It's important to remember, that listeners added through native addEventListener() aren't removed.

    on(btn).click += nextFrame;
    on(btn).click = prevFrame;

    In second line of above example the nextFrame handler was removed, and then prevFrame handler was added.

  4. Adding listeners

    Adding listeners

    (If you're here, you surely know how to add listeners in Fingers - sorry for duplicating).

    It's easy - you can add listeners, using following syntax
    on(btn).click += btn_clickHandler;

    Listeners added through on() can be removed using native removeEventListener() (it applies only to listeners with one e:Event argument):

    on(btn).click += someListener;
    btn.removeEventListener(MouseEvent.CLICK, someListener);
    trace(btn.hasEventListener(MouseEvent.CLICK)) // false;
    
  5. Removing listeners

    Removing event listeners

    Removing custom listener

    You can remove listeners added through on() or through addEventListener() with Fingers in a following way:
    // prepare
    btn.addEventListener(MouseEvent.CLICK, yourListener);
    // remove one listener
    on(btn).click -= yourListener+0;
    
    // or 
    btn.addEventListener(MouseEvent.CLICK, yourListener1);
    btn.addEventListener(MouseEvent.CLICK, yourListener2);
    // remove multiple listeners
    on(btn).click -= yourListener1 + yourListener2
    +0 is to omit compile error. In this way you can say compiler, to treat Function as an int. This could be done also in a way of simple cast: int(yourListener), however +0 version seems cleaner, shorter and more convenient to me. Another way to solve this is to turn off "strict compiler mode", but I wouldn't recommend that.

    Removing all listeners of one event type

    You can also remove at once all listeners of one event type, however this will only work for listeners added through on().
    
    // prepare
    on(btn).click += listener1;
    on(btn).click += listener2;
    on(btn).click += otherFunction;
    
    // remove all `click` listeners (added through on)
    on(btn).click = null;

    Removing all listeners

    What's more you can remove all listeners at once, but again, only those added through on().
    
    // prepare
    on(btn).click += btn_clickHandler;
    on(btn).mouseDown += btn_mouseDownHandler;
    on(btn).mouseUp += btn_mouseUpHandler;
    
    // remove all btn listeners (added through on)
    on(btn).removeAllListeners();
    
  6. Dispatching events

    Dispatcher

    Fingers can be used to dispatch native AS3 events (so they works, even if you use traditional addEventListener). So instead of such construction:

    btn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
    
    you can write:
    on(btn).click();
    
    This will work, however it's not exactly the same. Code above dispatches an instance of Event class, if you'd like to dispatch MouseEvent, you should write on(btn).click(MouseEvent);

    Method signature

    You can pass more parameters to dispatched event, as shown in the following method signature

    on(obj).<eventType>(eventClass:Class = flash.events.Event, ...eventParams);
    • eventType - type of event
    • eventClass - event class, e.g. MouseEvent, KeyboardEvent, ProgressEvent...
    • eventParams - all parameters passed in event constructor, without the first one (which is typically type:String)

    Example

    Assume, that we'd like to simulate download progress, by dispatching ProgressEvent

    on(loaderInfo).progress(ProgressEvent, false, false,  20,  200);
    //                           ↑           ↑     ↑      ↑      ↑
    //                           |        bubbles  | bytesLoaded |
    //                       eventType        cancealable    bytesTotal
    again, in pure AS3 that can be achieved with following code:
    loaderInfo.dispatchEvent(
        new ProgressEvent(ProgressEvent.PROGRESS, false, false, 20, 200)
    );
    
  7. Using freezer

    Freezer

    Sometimes we'd like to have a short syntax for making a handler from a function with custom arguments. In such cases, freezer becomes handy. You can call freezer in a following way:
    f$(yourFunction:Function)(args...)
    so, let's say we want our button to trace("button clicked") after clicking. We can achieve this, with one line:
    on(btn).click += f$(trace)("button clicked");
    It's same as if you'd write:
    on(btn).click += function():void {
    	trace("button clicked");
    }
    Freezer comes really handy when prototyping tweens, e.g. with Tweener:
    on(btn).click += f$(Tweener.addTween)(btn, {alpha: 0});

    Please note:

    • You can use f$ for any function, passing to it any number of arguments.
    • Freezer results are always different, so f$(someFunction)() != f$(someFunction)() is always true (same like with NaN).

  8. Restrictions

    Restrictions

    There are three restrictions, while using Fingers:

    1. Think about using Fingers like playing a toys. If you call on(...), you're getting your toys out a box. Then, after playing with them you need to clear up - pack them back into the box. That's why your operation should always end by calling any of Fingers actions:
      • operate on listener through -=, += , =,
      • removeAllListeners(),
      • getListenersNum(eventType:String).
      • getAllListenersNum().
      • dispatch event, using <eventType>() call.
    2. During on operation, use of complex functions factories is discouraged. That's because after calling on, your toys are out of a box and in some rare cases Functions are casted to Numbers, resulting in a more or less random integer.
    3. Maximum number of listeners added during ONE on operation equals to 16 (of course in overall you can have as many listeners as you wish).

Let me guess, open-source?

Yes. MIT license (free for commercial use).

Are Fingers ready to use in my project?

Although project is still fresh, it's found quite stable:

Are Fingers fast? What about size?

Fingers use AS3 native events, so they are as quick as native ones (during event dispatching/handling). However there is some overhead while using on(..).. statement, what I guess is tolerable in common cases.

Size is small - Fingers in your project add 2 kB to the resulting SWF.

Stay connected

If you wish to receive info about further development of Fingers or any other Flash & Flex stuff, you can follow me on Twitter, GitHub or blog.

Contribute

  1. Share Fingers with your friends.
  2. Let me know, where Fingers are used.
  3. Fork Fingers repo on GitHub.


Cheers,
Filip Zawada

@Filip_Zawada
me@filimanjaro.com


Last edited: Sat, 25 Feb 2012