Jeden z uživatelů DotVVM nám včera hlásil zajímavou chybu – pokud v komponentě GridView do některé z buněk umístíte tlačítko, a zároveň na řádky pověsíte RowDecorator, který na nich odchytává událost Click, při kliknutí na tlačítko se vyvolají obě dvě.
DotVVM totiž při použití tlačítka renderuje něco jako tohle:
<button onclick="dotvvm.postBack(…);return false;" />
Oprava byla velmi jednoduchá, ale přivedlo nás to k zajímavé otázce – jak vlastně to return false u event handlerů funguje? Chvilka hledání ukázala, že je v tom, jak už to ve světě Javascriptu bývá, slušný zmatek.
Každá událost, která v DOM nastane, vytvoří některý z Event objektů, kde o daném eventu najdete detaily. Ve všech prohlížečích kromě Firefoxu je tento objekt zpřístupněn pod window.event, a kromě toho je předán jako první parametr do funkce sloužící jako event handler. V HTML atributech (onclick) atd je dostupná jako proměnná event.
Takže pokud zaregistruji handler pomocí addEventListener, v první parametru dostanu patřičný event objekt. Akorát ve starých IE a bůhví kde ještě tohle přes attachEvent nefungovalo, takže se v různých frameworcích ustálila konvence dělat to nějak takto:
document.getElementById("button").addEventListener("click", myhandler);
function myhandler(e) {
e = e || window.event;
// ...
}
Pokud by náhodou do event handleru event objekt nebyl předán, dohledá se ve window.event, a budeme spoléhat na to, že browser bude mít implementováno jedno, nebo druhé.
Na event objektu pak můžete volat mimo jiné následující dvě funkce:
- preventDefault() – tato funkce zruší výchozí chování komponenty (např. přechod na adresu uvedenou v href atributu u odkazu nebo submitování formuláře).
- stopPropagation() – tato funkce zamezí propagaci této události do rodičovských elementů (standardně když tlačítko s onclick umístíte dovnitř divu, který bude mít také onclick, zavolají se oba – událost bublá směrem nahoru.
Pokud v handleru použijete return false, chová se to dost nekonzistentně:
- Pokud return false uvedete například v atributu onclick, zavolá se preventDefault(), ale stopPropagation() už ne.
- Pokud return false uvedete v event handleru navázeném přes addEventListener, nedělá to vůbec nic – defaultní chování se nepotlačí a událost bublá.
- Pokud return false uvedete v event handleru navázaném pomocí starého attachEvent (doporučuji nepoužívat), zavolá se pouze preventDefault().
- Pokud return false použijete v event handleru navázaném pomocí jQuery, zavolá to jak preventDefault() tak stopPropagation().