Der eigene Javascript Event Handler

17. Januar 2011
by Daniel Leeb

Besonders bei umfangreicheren Javascript-Umsetzungen zahlt es sich aus, eine kleine Bibliothek aus Hilfs-Funktionen und -Objekten zu entwickeln. Vorausgesetzt man möchte auf die Integration größerer Bibliotheken verzichten, muss man sich selbst um gewisse Grundfunktionen kümmern. Zu diesen zähle ich auch einen Event Handler.
Im folgenden möchte ich eine einfache Möglichkeit zeigen, einen solchen vielseitig einsetzbaren Event Handler umzusetzen.

Vorab einige Anforderungen an einen Event Handler:
- Jedes Objekt soll als Event Handler agieren können: Erweiterung (bzw. “Vererbung”) um Event Handler Funktionalität.
- Beliebige Events.
- Mehrere Listener bzw. Callbacks sollen an ein Event gebunden werden können.
- Benutzerdefinierte Daten beim Auslösen eines Events an die Listener übergeben.
- Übergabe von Rückgabewerten der Listener an das Event.

Implementierung

Zunächst ist es sinnvoll, aber natürlich nicht notwendig, ein Objekt zu erzeugen, welches als eine Art Namespace agiert, zum Beispiel:

1
window.li = window.li || {};

Ein leeres Objekt namens EventListener dient zum Identifizieren der Listener. Siehe dazu addListener() und deleteListener() weiter unten.

1
li.EventListener = function() {}

Nun kommt das eigentliche Basis-Objekt, welches später von Objekten “geerbt” wird.

1
li.BaseObject = function() {}

Wir verwenden das Javascript “prototype” Objekt, wodurch Instanzen von BaseObject um Methoden von dessen prototype erweitert werden.
Die erste Methode, defaults(), ist eine kleine Hilfsfunktion, um etwas komfortabler Default-Werte von Funktionsparametern setzen zu können.

1
2
3
4
5
6
li.BaseObject.prototype = {
    defaults: function(parameter, defaultValue, type) {
        if (typeof type === 'undefined')
            return (typeof parameter !== 'undefined') ? parameter : defaultValue;
        return (typeof parameter === type) ? parameter : defaultValue;
    },

Nun kommen die eigentlichen Methoden des Event Handlers:
Mit der Methode addListener() kann einem Event mittels Name eine Callback-Funktion zugewiesen werden:

1
2
3
4
5
6
7
8
9
10
    addListener: function(eventName, listenerCallback) {
        this.__listeners = this.defaults(this.__listeners, {});
        var listenerObj = new li.EventListener();
        this.__listeners[eventName] = this.defaults(this.__listeners[eventName], []);
        this.__listeners[eventName].push({
            listener: listenerObj,
            callback: listenerCallback
        });
        return listenerObj;
    },

Um Events auszulösen und somit alle Listeners aufzurufen muss einfach die Methode trigger() mit dem entsprechenden Eventnamen aufgerufen werden. Optional können hier beliebige Daten an die Listener übergeben werden. Die Rückgabewerte der Callback-Funktionen der Listener werden als Array zurückgegeben.

1
2
3
4
5
6
7
8
9
10
    trigger: function(eventName, data) {
        this.__listeners = this.defaults(this.__listeners, {});
        data = this.defaults(data, {});
        if (typeof this.__listeners[eventName] === 'undefined') return;
        var eventListeners = this.__listeners[eventName], retArr = [];
        for (var index in eventListeners) {
            retArr.push(eventListeners[index].callback.call(this, data));
        }
        return retArr;
    },

Die folgenden Methoden dienen nun noch zum Entfernen von Listener: entweder alle Listener, alle Listener eines Events oder ein bestimmter Listener (addListener() gibt ein EventListener Objekt zurück, welches zum Identifizieren von Listeners dient und der deleteListener() Methode übergeben werden kann).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    deleteAllListeners: function() {
        this.__listeners = {};
    },
    deleteListeners: function(eventName) {
        this.__listeners = this.defaults(this.__listeners, {});
        if (typeof this.__listeners[eventName] === 'undefined') return;
        delete this.__listeners[eventName];
    },
    deleteListener: function(listenerObj) {
        this.__listeners = this.defaults(this.__listeners, {});
        for (var index in this.__listeners) {
            for (var i in this.__listeners[index]) {
                if (this.__listeners[index][i].listener === listenerObj) {
                    this.__listeners[index].splice(i, 1);
                    return true;
                }
            }
        }
        return false;
    }  
}

Um ein Objekt, im folgenden li.MyObject, um diesen Event Handler zu erweitern kann etwa die extend()-Methode von jQuery verwendet werden:

1
jQuery.extend(li.MyObject.prototype, li.BaseObject.prototype);

Beispiel

Mit diesen wenigen Zeilen Code erhält man einen simplen aber vielseitig einsetzbaren Event Handler. Zum Abschluss ein kurzer Beispielcode bei dem das Objekt li.MyObject wie oben beschrieben um li.BaseObject erweitert wurde und somit als Event Handler agieren kann:

1
2
3
4
5
6
7
8
var obj = new li.MyObject;
// Binde eine anonyme Funktion an das Event mit dem Namen "myEvent"
obj.addListener('myEvent', function(data) {
    this.name = data.name;
    return data.name;
});
// Löse das Event "myEvent" aus: alle Listener werden aufgerufen und das Objekt { name: 'foo' } wird als Parameter übergeben.
obj.trigger('myEvent', { name: 'foo' });

Event Handler – Sourcecode

About

Daniel Leeb ist Mitarbeiter bei der Lorem Ipsum Mediengesellschaft m.b.H. und zuständig für die Neu- und Weiterentwicklung von Webanwendungen. Folgen Sie ihm via RSS.