Obsługa zdarzeń w aplikacjach JavaScript

Data publikacji: 2011-05-23 , Wyświetleń: 1717

js Czyli parę słów jak by to można zrobić.

 

Potrzeba

Jak wiemy potrzeba jest matką wynalazku. Podczas tworzenia aplikacji w JS często mam potrzebę wpięcia się w jakieś zdarzenie. Fajnie by było jakby można było sie dostać do tego zdarzenia w jakiś globalny sposób, wywołać metodę obsługi i zwrócić wynik.

 

Pierwsza myśl

Naturalnym rozwiązaniem tego zagadnienia wydaje się stworzenie obiektu z listą (nazwami) zdarzeń. Potem w miarę potrzeby w odpowiednim miejscu wywoływać metodę obsługi. Przykładowy kod:

var testApp = {
    events: {
        afterClick: function(){}
    },
    btn1Click: function(){
        alert('btn1 click');
        // wywołanie funkcji zdarzenia
        this.events.afterClick();
    },
    btn2Click: function(){
        alert('btn2 click');
        this.events.afterClick();
    }
};

Tak więc mamy przykładową strukturę obiektu aplikacji. Posiada ona 2 funkcje oraz gałąź ze zdarzeniami (events). Po wykonaniu jakiejś czynności podczas kliknięcia wywoływana jest funkcja z gałęzi events. W zdarzenie afterClick możemy wstawić własny kawałek kodu z jego obsługą, wystarczy proste przypisanie.

testApp.events.afterClick = function(){
    alert('Mój kod obsługi zdarzenia');
};

 

Rozwijamy myśl

Mamy już zaimplementowaną obsługę zdarzeń ale sam proces przypisywania naszych instrukcji do zdarzenia jest nie do końca fajny. Jakieś takie chodzenie po strukturze drzewa aplikacji. Można to przypisanie bardziej ustandaryzować - np tak:

var testApp = {
    events: {},
    bindEvent: function(eventName, eventCallback){
        this.events[eventname] = eventCallback;
    }
    // ... reszta kodu
};

I teraz bindowanie do zdarzenia wygląda tak:

testApp.bindEvent('afterClick', function(){
    alert('Event afterClick');
});

Wygląda to już bardziej czadowo ;-)

 

Jak się rozwijać to na całego

Bardziej dociekliwy umysł powiedziałby że wszystko fajnie ale co w przypadku kiedy zajdzie potrzeba wywołania większej ilości metod obsługi tego samego zdarzenia. Co jeżeli aplikacja bardzo dynamicznie przydziela metody obsługi poszczególnym zdarzeniom? Można to rozwiązać tak że bindowanie będzie dodawało wpis do tablicy konkretnego zdarzenia. Trzeba lekko zmodyfikowac dotychczasowy kod:

var testApp = {
    events:{
        afterClick:[]
    },
    bindEvent: function(event, callback) {
        this.events[event].push(callback);
    }
};

Dodatkowo aby ułatwić sboie wyzwalanie metod eventu napisana można napisać procedurę obsługi tego zadania:

var testApp = {
    // ...
    runEvent: function(event){
        if (this.events[event] && this.events[event].length > 0) {
            for (var i=0; i<this.events[event].length; i++) {
                this.events[event][i].call(this, arguments);
            }
        }
    },
    // ...
};

Metoda call uruchamia pojedyncza funkcję przekazując do niej kontekst naszej aplikacji oraz parametry z jakimi została wywołana funkcja runEvent (czyli wrzuca nazwę eventu). Teraz wywołanie wszystkich funkcji obsługi sprawoadza sie do prostego i czytelnego kodu:

testApp.runEvent(
    'afterClick',
    // możemy przekazać dodatkowe parametry ....
    100,
    {ala:'ma kota'}
);

 

Grupowanie

Może to już przesada ale wpadło mi do głowy, że zdarzenia można by grupować w obrębie tesgo samego zdarzenia. Do tablicy zdarzenia nalezy oprócz metody obsługi przekazać nawę grupy. Lekka modyfikacja kodu dodawania i wywoływania event-u:

var testApp = {
    events:{
        afterClick:[]
    },
    runEvent: function(event, grp){
        if (this.events[event] && this.events[event].length > 0) {
            for (var i=0; i<this.events[event].length; i++) {
                if (this.events[event][i].group = grp) {
                    this.events[event][i].callback.call(this, arguments);
                }
            }
        }
    },
    bindEvent: function(event, grp, cb) {
        this.events[event].push({group: grp, callback: cb});
    }
    // ...
};

Przykład dodania i wywołania zdarzenia:

// dodanie 
textApp.bindEvent('afterClick', 'testGroup1', function(){
    alert('Event1: testGroup1');
});
textApp.bindEvent('afterClick', 'testGroup1', function(){
    alert('Event2: testGroup1');
});

textApp.bindEvent('afterClick', 'testGroup2', function(){
    alert('Event1: testGroup2');
});

// uruchomienie
textApp.runEvent('afterClick', 'testGroup1'); // 2 komunikaty
textApp.runEvent('afterClick', 'testGroup2'); // 1 komunikat

 

Fajna zabawka ;-)

Tagi: zdarzenia, javascript