10
May 07

JavaScript, Events, IE

Nota: am ceva probleme cu WordPress & pre-code tags, asa ca formatarea codului nu e nici best-practice nici cum arata ea in realitate, in codul meu ;) .

Aurelian a scris ieri despre frustrarile pe care i le-a adus Internet Explorer in atribuirea dinamica de evenimente pentru elemente HTML.
Am scris un raspuns destul de consistent pe blog-ul sau, dar s-a pierdut printre request-uri (HTTP)... Dar am avut si eu de-a face cu problema asta si ma gandeam sa prezint solutia gasita.

Studiu de caz

Intr-o aplicatie la care lucrez, am de luat din baza de date o serie de date, printr-un request Ajax. Script-ul PHP apelat, trimite inapoi array-ul de date in format JSON. Pentru fiecare element, clonez un nod din DOM (pe post de template) care are, la randul sau, sub-elemente. Atribui frumos diferite proprietati (id, href, src etc.) elementelor din acel nod si il injectez inapoi in document, unde am nevoie de el. Toate bune si frumoase! Pe Firefox. :)

Prima problema in IE
In procesul de parcurgere a JSON-ului primit de la server, am nevoie sa atribui unor elemente cate-un eveniment onclick, asa ca cel mai la-ndemana mi-a fost: element.setAttribute("onclick", "foo();"); Concret, am facut ceva de genul:

/* response contine obiectul JSON, care arata cam asa:
{ "children": [
{"id": 1, "title": "cool title 1"},
{"id": 2, "title": "cool title 2"},
{"id": 3, "title": "cool title 3"}
] }
*/
for(i = 0; i < response.children.length; i++)
{
// multe alte instructiuni...
// "element" este un element de tip anchor (a)
element.setAttribute("onclick", "performAction(" +
response.children[i].id + ")");
}
Atribuirea asta merge fara probleme pe Firefox, dar in IE nu se intampla nimic. Nici o problema, am zis, folosesc o functie generica de event handling, care sa identifice browser-ul si sa foloseasca metoda corespunzatoare browser-ului curent:
function _attachEvent(elem, eventName, handler) {
if (elem.attachEvent) {
return elem.attachEvent("on" + eventName, handler);
} else if (elem.addEventListener) {
elem.addEventListener(eventName, handler, false);
return true;
} return false; }
A doua problema cu IE

Ce am descoperit (dupa multe experimente si cautari pe Google) e ca in Internet Explorer (6) atribuirea de elemente se face dupa ce se executa tot codul JavaScript. E ca si cum s-ar face intr-un thread paralel.
Adica in timp ce in Firefox, fiecare element din acel loop primea un eveniment onclick, in IE doar un singur element primea acel eveniment, dar ca si cum l-as fi atribuit la terminarea acelui for (deci i = response.children.length). Complet aiurea!

Solutia gasita
Experimentand variante impreuna cu Bogdan, seful meu, am hotarat sa facem urmatorul artificiu:
<a href="#" id="element_28"
onclick="performAction(this.id.split('_')[1]);">
Am atribuit dinamic (cu element.setAttribute()) id-ul si am “hardcodat” onclick in acel nod template, pe care l-am clonat. Functioneaza perfect, desigur. :)

Ce experiente aveti cu cross-browser JS?

  • Marian

    Pentru IE
    in loc de element.setAttribute("onclick","text")
    trebuie sa utilizati
    element['onclick']=new Function("text");
    Succes
    :)

  • Ar fi interesant de stiut daca problema asta s-ar putea rezolva si cu "event-selectors":http://www.encytemedia.com/eve..., din pacate nu am avut timp sa testez, si e mai greu de introdus o librarie noua intr-o aplicatie gata in proportie de 90%.

  • Da, daca ai un singur eveniment de atasat si unui singur element, e OK. Dar daca ai de atasat event-uri elementelor unui array, aici incepe distractia!

  • Pana la urma eu am ales solutia cu functia anonima atasata pentru evenimentul care m-a interesat.

    Cross-Browser JS inseamna rezolvarea unor probleme "neasteptate" pentru IE, si din pacate uneltele de debug existente pentru acest browser nu se ridica la nivelul lui "Firebug":http://getfirebug.com/ pentru Firefox.
    Apoi, am impresia ca multe din aceste probleme nu sunt documentate suficient.
    Practic ai nevoie de un prieten programator full-time in javascript pentru IE :)

blog comments powered by Disqus