JavaScript jak wiemy powstał po to by zapewnić stronom WWW interaktywność. Jest ona realizowana dzięki zdarzeniom. O ile w wypadku elementów strony mamy do dyspozycji gotowe zdarzenia (charakterystyczne dla danego elementu), to w wypadku klas tworzonych przy użyciu Class, musimy sami zadbać o zdarzenia. Wymaga to zarówno zadbania o zdefiniowanie zdarzenia, jak i momentu w którym jest ono wywoływane, a także opcjonalnego usunięcia zdarzenia. Zatem w wypadku klas jest to zadanie trudniejsze niż w wypadku "gotowych" elementów strony, gdzie musimy właściwie przypisać funkcję do danego zdarzenia i na tym nasze zadanie się kończy, ale w zamian możemy tworzyć takie zdarzenia jakie tylko zechcemy (oczywiście ograniczone możliwościami JavaScript ;).

Co będzie potrzebne ?

Podobnie jak w wypadku klasy Options, aby dodać zdarzenia do klasy musimy do właściwości Implements dodać stosowną wartość:

var przykladowaKlasa = new Class({
    Implements: Events,
    //... dalszy kod klasy
});

Oczywiście, jeżeli chcemy używać możliwości klas Options i Events naraz stosujemy we właściwości Implements tablicę klas:

var przykladowaKlasa = new Class({
    Implements: [Events, Options],
    //... dalszy kod klasy
});

Dodajemy zdarzenie do klasy

Jeżeli ktoś pamięta klasy takie jak Fx.Base czy XHR z MooTools 1.1(1), to powinien kojarzyć takie nazwy jak onSuccess, onRetry, onComplete itd.

Wszystko to było zdarzeniami zdefiniowanymi na potrzeby danej klasy. Poszerzało to znacznie nasze możliwości użycia tych klas, ponieważ mogliśmy na przykład bez problemu określić co się stanie po wykonaniu się animacji czy asynchronicznego zapytania.

Zdarzenia dla klasy możemy dodawać pojedyńczo dzięki metodzie addEvent, lub po kilka naraz dzięki metodzie addEvents.

Zacznijmy od prostszej w składni z tych dwóch metod - addEvent:

przykladowaKlasa.addEvent("zdarzenie", wywolywanaFunkcja);

W wypadku metody addEvents jako argument stosujemy obiekt:

przykladowaKlasa.addEvents({
    "zdarzenie1" : wywolywanaFunkcja1,
    "zdarzenie2" : wywolywanaFunkcja2
});

Taka konwencja (stosowanie obiektu) jest używana wszędzie tam, gdzie w MooTools robi się kilka rzeczy naraz - zatem warto się do niej przyzwyczaić ;)

Stwórzmy sobie lampkę

Pora na przykład - stworzymy klasę Lampka, która będzie posiadać dwa zdarzenia: onOn i onOff , właściwość status oraz metody switch i initialize:

var Lampka = new Class({
    Implements: Events,
 
    initialize: function(){
        this.status = 'off';   
    },
 
    switcher: function(){
        this.status = (this.status == 'on') ? 'off' : 'on';
    }
});
 
Lampka.addEvent("on", function(){
    alert("Lampka została włączona.");
});
 
Lampka.addEvent("off", function(){
    alert("Lampka została zgaszona.");
});

Parę uwag do powyższego kodu - nazwy zdarzeń podawanych jako argumentu metod addEvent i addEvents piszemy z małej litery, dodatkowo kod dodawania zdarzeń można zapisać na inne sposoby:

var Lampka = new Class({
    Implements: Events,
 
    initialize: function(){
        this.status = 'off';   
    },
 
    switcher: function(){
        this.status = (this.status == 'on') ? 'off' : 'on';
    }
});
 
Lampka.addEvents({
    "on": function(){
        alert("Lampka została włączona.");
    },
 
    "off": function(){
        alert("Lampka została zgaszona.");
    }
});

lub:

var Lampka = new Class({
    Implements: Events,
 
    initialize: function(){
        this.status = 'off';
 
        this.addEvents({
            "on": function(){
                alert("Lampka została włączona.");
            },
 
            "off": function(){
                alert("Lampka została zgaszona.");
            }
         });   
    },
 
    switcher: function(){
        this.status = (this.status == 'on') ? 'off' : 'on';
    }
});

I tak dalej - ważne by zdarzenia były zdefiniowane przed ich wywołaniem.

Wszystko ładnie pięknie, ale na dobrą sprawę gdy wywołamy kod:

var zielonaLampka = new Lampka();
zielonaLampka.switcher();

To nie wiemy do końca jaki jest status lampki - bo gdy przypiszemy kod zielonaLampka.switch() do zdarzenia kliknięcia przycisku, to po kilku przypadkowych kliknięciach nie wiemy co się z naszą wirtualną lampką dzieje - świeci czy nie ?

Wywołajmy zdarzenie

Aby jakoś klarownie pokazać, że lampka świeci lub nie wykorzystajmy zdarzenia dodane do naszej klasy Lampka: onOn i onOff.

Wywołanie zdarzenia jest proste - służy do tego metoda fireEvent, która pobiera trzy argumenty:

this.fireEvent("zdarzenie", argumenty, opoznienie);

Pierwszy argument jest obowiązkowy i zapisujemy go tak jak w wypadku metod addEvent i addEvents, drugi argument to albo zwykły argument przekazywany funkcji obsługi zdarzenia (jeżeli tego wymaga), albo tablica argumentów, gdy potrzeba ich więcej niż jeden. Opóźnienie to oczywiście czas po jakim zostanie wywołana funkcja obsługi zdarzenia.

My skupimy się na najprostszym wywołaniu - dodatkowe parametry i tak już znamy z omówienia obiektu Function.

Dodajmy zatem wywoływanie zdarzeń do naszej klasy Lampka:

var Lampka = new Class({
    Implements: Events,
 
    initialize: function(){
        this.status = 'off';   
        this.addEvents({
            "on": function(){
                alert("Lampka została włączona.");
            },
 
            "off": function(){
                alert("Lampka została zgaszona.");
            }
        });   
    },
 
    switcher: function(){
        this.status = (this.status == 'on') ? 'off' : 'on';
        this.fireEvent((this.status == 'on') ? 'on' : 'off');
    }
});

Po wykonaniu kodu:

var zielonaLampka = new Lampka();

Możemy do woli używać kodu:

zielonaLampka.switcher();

Mając pewność, że zawsze uzyskamy prawidłową informację o stanie lampki.

Usuwanie zdarzeń

Czasem może zajść potrzeba usunięcia zdarzeń - podobnie jak w wypadku ich dodawania istnieją dwie metody do ich usuwania - removeEvent i removeEvents - pierwsza metoda usuwa pojedyńcze zdarzenie, a druga usuwa kilka zdarzeń naraz. Przy czym są usuwane tylko te zdarzenia, których funkcje obsługi nie mają właściwości internal ustawionej na wartość logiczną true.

Ja osobiście polecam stosowanie metody removeEvents, ponieważ jest mniej problematyczna - nie wymaga podawania funkcji jak w wypadku funkcji removeEvent:

obiekt.removeEvent("zdarzenie", uchwytDoFunkcji);

Natomiast metoda removeEvents pozwala określić sposób usuwania zdarzeń - jedno albo wszystkie:

obiekt.removeEvents("zdarzenie");

Powyższy kodu usunie jedno zdarzenie (jeżeli funkcja tego zdarzenia ma właściwość internal równą false), a zapis:

obiekt.removeEvents();

Usunie wszystkie zdarzenia, których funkcje mają określoną właściwość internal jako false.

Zatem aby usunąć z naszej lampki zdarzenie onOff wystarczy zapis:

zielonaLampka.removeEvents("off");

Aby usunąć oba zdarzenia zapiszemy po prostu:

zielonaLampka.removeEvents();

Po wykonaniu powyższego kodu nie zobaczymy więcej skutków wywołania naszych zdarzeń.

Kiedy stosować ?

Wszystko wygląda pięknie, ale zapewne znajdą się osoby nieprzekonane do klasy Events - w końcu zawsze zamiast korzystać ze zdarzeń wystarczy zapisać:

var Lampka = new Class({
    initialize: function(){
        this.status = 'off';   
    },
 
    switcher: function(){
        this.status = (this.status == 'on') ? 'off' : 'on';
       alert((this.status == 'on') ? "Lampka została włączona.") : "Lampka została zgaszona.");
    }
});

Jak widać jest o wiele krócej. Sprawa użycia klasy Events wygląda podobnie jak w wypadku klasy Options - trzeba ją stosować zależnie od sytuacji.

Jeżeli potrzebujemy usuwać zdarzenia to warto skorzystać z klasy Events - nie musimy wtedy kombinować ze zmiennymi, usuwaniem funkcji itp.

Warto jeszcze wspomnieć, że wielka zaleta klasy Events ujawnia się w momencie sprzężenia jej z klasą Options:

var Lampka = new Class({
    Implements: [Events, Options],
 
    options:    {
        "onOn": function(){
                alert("Lampka została włączona.");
            },
 
        "onOff": function(){
            alert("Lampka została zgaszona.");
        }
    },
 
    initialize: function(options){
        this.status = 'off';  
        this.setOptions(options);
    },
 
    switcher: function(){
        this.status = (this.status == 'on') ? 'off' : 'on';
        this.fireEvent((this.status == 'on') ? 'on' : 'off');
    }
});

Powyższy kod sprawi, że użytkownik może określić własny sposób działania zdarzeń onOn i onOff:

var zielonaLampka = new Lampka({
    onOn: function(){
        alert(1);
    },
 
    onOff: function(){
        alert(0);
    }
});

A gdy ich nie określi ? Wtedy zostaną wywołane standardowe funkcje obsługi zdarzeń zdefiniowane w opcjach klasy.

Warto pamiętać, że dla zdarzeń, których obsługa jest opcjonalna (to znaczy autor klasy domyślnie nie chce by w momencie wystąpienia zdarzenia coś się działo), najlepiej opisać jako funkcję $empty znaną nam z podstaw MooTools (bo jest to krótsze niż zapis z pustym function).

Podsumowanie

Wiemy już sporo o możliwościach klas w MooTools 1.2, - w tej kwestii pozostała nam jeszcze do omówienia klasa Chain, która zajmiemy się w następnej części kursu.

Komentarze do wpisu "MooTools 1.2 - klasa Events":

1. Bigismall napisał(a):
29 lipca 2008, 07:18:09

Kolejny udany wpis. Tak przy okazji, to właśnie eventy i próby dotarcia do elementu generującego, przyprawiały mnie o białą gorączkę w czystym JS.

Dodaj komentarz:

Textile Lite włączony ( szczegółowy opis znaczników ):
*strong* | # lista numerowana | * lista wypunktowana | _em_ | __italic__ | "link":http:// | bq. cytat.