Eventhandler stellen benötigte Daten bereit
Problem
Sie wollen, dass andere Plugins (oder einfach irgendwelcher jQuery-Code) aufgerufen werden können und bestimmte Variablen verändern, bevor Sie die eigentliche Aufgabe angehen.
Lösung
Nutzen Sie Events, um andere Skripten über die Aktion zu informieren, die durchgeführt werden soll.
Es ist möglich, Daten von den »aufgerufenen« Eventhandlern zu erhalten.
Wenn keine angegeben werden, können Sie eigene Standard-Optionen angeben.
Der Weg zur Lösung ist abhängig von der verwendeten jQuery-Version.
Diskussion
Wie kann man das mit jQuery 1.3 und höher machen?
Seit jQuery 1.3 lässt sich dies durch
jQuery.Event
leichter erledigen. Der alte Weg
funktioniert immer noch für triggerHandler()
, aber nicht für jQuery.trigger()
.
Für den folgenden Code müssen wir ein
jQuery.Event
erzeugen:
var e = jQuery.Event('updateName');
Um jetzt die Handler aufzurufen und den Wert zu
erhalten, übergeben wir das Event-Objekt an trigger()
und holen uns danach die Daten:
jQuery('#element').trigger(e);
alert( e.result ); // Charles
Wie schon zu Beginn gesagt funktioniert das nicht so toll, wenn man viele Handler gebunden hat – dann ist das Ganze oft etwas unzuverlässig und fragil.
Wie können wir also zwischen den Eventhandlern und der auslösenden Funktion kommunizieren?
Nun, über das Event-Objekt, das wir übergeben.
Das an trigger()
übergebene Objekt jQuery.Event
ist das
gleiche, das jeder Handler als erstes Argument erhält.
Wir können also wie folgt vorgehen:
jQuery('#name').bind('updateName', function(e){ e.name = this.value; }); var e = jQuery.Event('updateName'); jQuery('#name').trigger(e); alert( e.name );
Das Beispiel unterscheidet sich nicht sehr von
einer einfachen Zuweisung an e.result
,
aber was ist bei mehreren Eventhandlern, die mit dem gleichen
Event-Objekt arbeiten?
jQuery('#first').bind('update', function(e){ e.firstName = this.value; }); jQuery('#last').bind('update', function(e){ e.lastName = this.value; }); var e = jQuery.Event('update'); jQuery('#first, #last').trigger(e); alert( e.firstName ); alert( e.lastName );
Wir haben also eine Möglichkeit, eine beliebige
Zahl von Eventhandlern zu nutzen, um die erforderlichen
Informationen für eine Funktion zusammenzustellen. Sie können
natürlich trigger()
mehrfach aufrufen
und dabei immer das gleiche Event-Objekt mitgeben.
Wie schon gesagt ist es sinnvoll, das Event-Objekt mit Standardwerten vorzubelegen (wenn es passende gibt). Ihr Code sollte sich nicht darauf verlassen, dass andere sich für ein bestimmtes Event registriert haben.
Können keine Standardwerte genutzt werden, dann können Sie immer noch den Aufruf abbrechen oder einen Fehler werfen.
Vorgehen vor jQuery 1.3
Bei älteren Versionen von jQuery konnte der
Anwender nur einen einzelnen Wert erhalten, der beim Aufruf von
jQuery.trigger()
und/oder triggerHandler()
zurückgegeben wurde.
Das ganze sah dann in etwa so aus:
jQuery('#element').bind('updateName', function(){
return 'Charles';
});
var name = jQuery('#element').triggerHandler('updateName');
alert( name ); // Charles
Das war ausreichend, wenn Sie nicht mehr als einen Eventhandler hatten, der Daten zurückgab. Bei mehreren Handlern entschied der letzte der aufgerufenen Handler, welche Daten zurückgegeben wurden.
Eventhandler können Aktionen verhindern
Dies ist noch eine Spezialisierung dessen, was
wir schon gesehen haben. Event-Objekte haben immer eine Methode
namens preventDefault()
. Diese Methode wird für
die eingebauten Events genutzt, um die normalen Aktionen zu
unterbinden, wie zum Beispiel beim Klicken auf einen Link. Bei
eigenen Events gibt es aber hierfür keine sinnvolle Anwendung.
Wir können daraus einen Vorteil ziehen und diese Methode nutzen, um es anderen Skripten zu erlauben, Aktionen zu verhinden, die ausgeführt werden sollten.
Ich werde Ihnen ein Beispiel dafür zeigen und das in Das globale Auslösen von Events beschleunigen vorgestellte Mini-Plugin nutzen, was für die Anwendung dieser Methode allerdings keine Voraussetzung ist:
var remote = jQuery.listener({ request:function( url, callback ){ jQuery.ajax({ url:url, success:callback }); } }); // Anforderung abschicken remote.request('contact.html', function( html ){ alert( html ); });
Stellen Sie sich jetzt vor, dass wir es einem
externen Skript erlauben wollen, bestimmte Anforderungen bei Bedarf
abbrechen zu können. Dazu müssen wir remote.request
wie folgt anpassen:
var remote = jQuery.listener({ request:function( url, callback ){ var e = jQuery.Event('beforeRequest'); e.url = url; this.trigger(e); if( !e.isDefaultPrevented() ) jQuery.ajax({ url:url, success:callback }); } });
e.isDefaultPrevented()
gibt zurück, ob
e.preventDefault()
für dieses Objekt
aufgerufen wurde.
Ein externes Skript kann nun Folgendes tun:
remote.bind('beforeRequest', function(e){
if( e.url == 'contact.html' )
e.preventDefault();
});
Durch die Rückgabe von false (innerhalb der
Funktion) erzielt man nahezu den gleichen Effekt wie beim Aufruf
von e.preventDefault()
. Auch damit
wird die Weiterverteilung des Events abgebrochen, was durchaus
erwünscht sein kann.
In solchen Situationen kann man natürlich auch ein Anpassen der URL (oder der Post-Daten, wenn es welche gibt) durch Handler zulassen.