• Recherchez sur css4design

Utilisez le DOM et Javascript comme un chef

Appliquer une fonction selon la classe CSS

C’est génial ! me suis-je écrié lorsque tout fut mis en place. Cette fonction serait, à n’en pas douter, d’une redoutable efficacité pour appliquer n’importe quelle fonction Javascript à n’importe quel élément.

J’allais me mettre au clavier pour vous annoncer la bonne nouvelle, quand je me suis dit : C’est bien beau tout ça, mais ne serait-ce pas mieux de pouvoir appliquer une fonction selon la classe, de manière à rendre cette fonction encore plus sympathique ?

C’est ainsi que bien plus tard, je me suis retrouvé sur le site de Robert Nyman en train de décortiquer la fonction getElementsByClassName() pour l’intégrer à ma fonction defineEventInContainer() ! Ce qui donne, si nous voulons récupérer tous les liens avec la classe info-liens contenus dans le document :

function defineEventByClass() {
    var arrReturnElements = getElementsByClassName(document, "a", "info-liens");
    var intReturnElements = arrReturnElements.length;
    for (var i=0; i<intReturnElements; i++) {
        arrReturnElements[i].onclick = toto1;
    }
}

Le seul changement apparent est le remplacement de document.getElementById(…) par getElementsByClassName(…). J’ai écrit en apparence, car ce getElementsByClassName ne fait pas partie du DOM. C’est là tout le génie de Robert Nyman et Jonathan Snook d’avoir écrit une fonction que l’on peut utiliser de façon transparente. Sous le capot on peut lire :


function getElementsByClassName(oElm, strTagName, oClassNames) {
    var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
    var arrReturnElements = new Array();
    var arrRegExpClassNames = new Array();
    if(typeof oClassNames == "object") {
        for(var i=0; i<oClassNames.length; i++) {
            arrRegExpClassNames.push(new RegExp("(^|\s)" + oClassNames[i].replace(/-/g, "\-") + "(\s|$)"));
        }
    }
    else {
        arrRegExpClassNames.push(new RegExp("(^|\s)" + oClassNames.replace(/-/g, "\-") + "(\s|$)"));
    }
    var oElement;
    var bMatchesAll;
    for(var j=0; j<arrElements.length; j++) {
        oElement = arrElements[j];
        bMatchesAll = true;
        for(var k=0; k<arrRegExpClassNames.length; k++) {
            if(!arrRegExpClassNames[k].test(oElement.className)) {
                bMatchesAll = false;
                break;
            }
        }
        if(bMatchesAll) {
            arrReturnElements.push(oElement);
    }
    }
    return (arrReturnElements)
}
// --- // Array support for the push method in IE 5
    if(typeof Array.prototype.push != "function") {
        Array.prototype.push = ArrayPush;
    function ArrayPush(value) {
        this[this.length] = value;
    }
     }

Les deux cerises sur le gâteau sont la possibilité d’utiliser des noms de classe avec un tiret entre deux mots, ainsi que le support des classes multiples appliquées à un élément. Ainsi, pour récupérer tous les éléments possédant les classes chaussettes, roses, et help au sein de la balise dont l’id est intro, on utilisera la fonction defineEventByIdAndClasses() :

function defineEventByIdAndClasses() {
    var arrReturnElements = getElementsByClassName(document.getElementById("intro"), "*", ["chaussettes", "roses", "help"]);
    var intReturnElements = arrReturnElements.length;
    for (var i=0; i<intReturnElements; i++) {
        arrReturnElements[i].onclick = toto3;
    }
}

Le changement affecte la même ligne : nous plaçons dans la variable arrReturnElements, le résultat de la fonction getElementsByClassName(), avec les arguments adéquats. Notez l’utilisation du sélecteur universel *, le joker pour spécifier n’importe quel élément XHTML.

Pour cibler les élément abbr avec la classe info, le résultat de la fonction getElementsByClassName(document.getElementById(”intro”), “abbr”, “info”) sera affecté à la variable arrReturnElements.

A vous de jouer maintenant

Voilà, c’est presque terminé. Il ne manque qu’un petit exemple fonctionnel histoire de constater que tout marche comme prévu et de faire un peu de pub à ma page loupanthère ;)

The Ultimate getElementsByClassName
http://www.robertnyman.com/…
http://www.snook.ca/jonathan
La fonction getElementsByClassName ultime…
A propos du DOM
http://openweb.eu.org/dom/
Un bon point de départ pour commencer ;)
http://fr.wikipedia.org/wiki/Document_Object_Model
wikipédia, toujours de bon conseil
http://xmlfr.org/w3c/TR/REC-DOM-Level-1/
La bible du DOM traduite en français
A propos de Javascript
http://www.w3schools.com/js/
JavaScript is easy to learn! You will enjoy it!
http://www.aidejavascript.com/
Une bonne référence en français pour découvrir Javascript
http://www.devguru.com/technologies/javascript/home.asp
Site en anglais clair et structuré pour continuer l’apprentissage de Javascript
This entry was posted in Javascript & PHP and tagged , , , , , . Bookmark the permalink. Trackbacks are closed, but you can post a comment.

25 Comments

  1. Posted 05/10/2006 at 09:54 | Permalink

    Effectivement très utile !

    Et maintenant, pour éviter le <body onload…> tu as aussi

    try{window.onload=function(){loadDivs();}}
    catch(e){window.attachEvent("onload", loadDivs);}

    On peut aussi imaginer passer le nom de la function à exécuter en paramètre de defineEventByClass…

    Rhaaa la la c’est bien inspirant tout ça !

  2. Posted 05/10/2006 at 09:56 | Permalink

    J’oubliais… "loadDivs" étant une function dans laquelle on regroupe tout ce qui se lance au chargement de la page, c’est un exemple, pas quelque chose qui existe, hein /o\

  3. Posted 05/10/2006 at 10:17 | Permalink

    Tout ça pour Toto … Quel veinard ^^

  4. Posted 05/10/2006 at 10:48 | Permalink

    @Talou -> Merci pour le try… catch. Dans loadDivs() je mets quoi exactement ? Des fois, faut m’expliquer comme si j’avais 5 ans…
    @xuxu -> Toto insistait, alors… Au fait, sympa les bannières Copaing.net ^^ Ca me donne une idée ;)

  5. Posted 05/10/2006 at 16:14 | Permalink

    ça parle de quoi ici?

  6. Posted 05/10/2006 at 16:26 | Permalink

    @thanh -> Si aussi tu codais un peu plus, au lieu de serrer des mains et de distribuer des cartes… :p

  7. Posted 05/10/2006 at 16:28 | Permalink

    Ben justement j’avais vu de la lumière j’ai cru qu’on servait à boire!

  8. Posted 05/10/2006 at 16:57 | Permalink

    Vivement le vin, donc ;)

  9. Posted 05/10/2006 at 21:25 | Permalink

    Encore plus fort ! Si tu veux supprimer le javascript de ton doc html, tu peux carrément utiliser la fonction addevent de Scott Andrew (http://www.scottandrew.com/weblo...

    function addEvent(obj, evType, fn){
    if (obj.addEventListener) {
    obj.addEventListener(evType, fn, true);
    return true;
    } else if (obj.attachEvent) {
    var r = obj.attachEvent("on"+evType, fn);
    return r;
    } else {
    return false;
    }
    }

    où obj est ton element html,
    evType, ton type d’évènement (click, over, out…)
    et fn, la fonction que tu appelles.

    Par exemple pour initier un script dans un doc html, tu peux faire
    addEvent(window, ‘load’, maFonction);

    et là, c’est vraiment Magic !

  10. Posted 05/10/2006 at 22:28 | Permalink

    @Gregoire -> Je connaissais pas du tout cette méthode addEventListener qui a l’air aussi puissante que subtile. Je teste dès que possible !

    P.S. Le web c’est génial : c’est quand tu crois avoir compris un truc, que tu découvres des choses vraiment intéressantes ;)

  11. Posted 05/10/2006 at 23:55 | Permalink

    Et si vraiment t’as pas compris, reprend un verre!

  12. Posted 06/10/2006 at 00:14 | Permalink

    lol, pour ça, je crois que je ferais mieux d’attendre l’apéro-blog du 20 :)

  13. Posted 06/10/2006 at 00:34 | Permalink

    br1o : j’ai mis une function qui s’appelle loadDivs, ok, mais elle peut s’appeler autrement, et dedans tu mets toutes les fonctions que tu veux charger au démarrage… Admettons que tu aies besoin d’attacher une action à tous les éléments de class XX et et une autre action à tous les éléments de class YY, eh bien tu as une fonction

    function start()
    {
    defineEventByClass("img_foo", "f_foo");
    defineEventByClass("div_bar", "f_bar");
    }

    en admettant que la fonction defineEventByClass permette de définir en paramètres le nom de class et le nom de la fonction à appeler dans ce cas…

    Ca marche aussi avec l’astuce encore plus élégante de Grégoire.

  14. Bewonder
    Posted 22/10/2006 at 17:49 | Permalink

    Merci pour ces informations, l’astuce de Gregoire étant trés "élégante".

    Par contre, je me heurte à un problème… le passage de paramètres.
    En gros, j’ai un système de navigation par boutons images.
    Chaque bouton doit valider le formulaire de la page actuelle avant d’être redirigé.
    Je voudrais que ma fonction "toto" récupère des informations fixées pour chaque lien (appel de la nouvelle page) et permette la validation du formulaire.

    J’ai eu l’idée de coller ces paramètres (du style "11" pour la page 1-1 ou "12" pour la page 1-2…) dans le paramètre ID de chaque lien.
    Mais impossible de récupérer la valeur de l’id du lien cliqué.

    ex :
    <div id="images">
    <a id="11"…><img…></a>
    <a id="12"…><img…></a>

    </div>

    et l’appel de la fonction : onload="addEvent(images, ‘click’, toto, this.id);"

    Mais ça ne marche pas, this.id ne semble pas être possible d’obtenir comme ça.

    Merci pour vos commentaires.

  15. Bewonder
    Posted 23/10/2006 at 15:51 | Permalink

    Bon, comme je dois me débrouiller seul…
    Voilà ce que j’ai fait :

    Dans chaque formulaire (dans chaque page donc) je créé deux champs cachés (page et etape).
    Sur mes liens, je créé un évenement onMouseOver qui renseigne ces valeurs à chaque passage de la souris.
    J’ai repris la première fonction de br10, toto renseigne la valeur document.forms['form1'].action avec l’état actuel de chaque champ caché puis poste le formulaire.

    Voilà, ce n’est peut être pas trés élégant mais ça marche.

  16. Posted 23/10/2006 at 17:57 | Permalink

    Bonjour Bewonder,
    Quand je n’ai pas la réponse à une question, je laisse passer un peu de temps au cas où quelqu’un d’autre aurait une solution. Concernant la façon dont tu as résolu ton problème, je n’ai pas mieux à proposer ;) Well done !

  17. irongomme
    Posted 22/11/2006 at 16:48 | Permalink

    Bonjour à tous,

    C’est fort sympathique de pouvoir redefinir les evenement mais je suis confronté au meme probleme que bewonder, c’est a dire que si je reprend l’exemple ici, il faudrait que ma methode toto puisse avoir acces au moins à l’instance de l’objet qui la declenche … y a t’il un moyen de pouvoir faire ca ?

    ou peut t’on tout simplement envoyer des parametres dans la methode toto ?

    merci.

  18. irongomme
    Posted 22/11/2006 at 20:28 | Permalink

    J’ai trouvé la solution !!

    exemple :

    document.getElementById(’machin’).onclick = function() { toto(argument1, argument2, etc…); };

    Ca peut être utile pour ceux qui devellope à la façon AJAX sans framework ! On peut élaborer de véritables applications en couplant ça avec du php.

    Tchao

  19. Posted 22/11/2006 at 20:50 | Permalink

    Bravo et merci de la part de tout ceux qui bloquaient dessus ;)

  20. yafa
    Posted 02/01/2007 at 23:01 | Permalink

    bonjour, es que vous pouvez m’indiquer des docs important concernant le dom..
    merci

  21. br1o
    Posted 03/01/2007 at 07:50 | Permalink

    Bonjour yafa, concernant le dom, voici quelques liens supplémentaires :
    slayeroffice.com/articles…
    nyams.planbweb.com/dom.ht…
    gilles.chagnon.free.fr/co…

  22. Posted 25/06/2008 at 13:35 | Permalink

    Salut Bruno! Décidément j’arrive toujours a me retrouver chez toi :D juste pour te signaler que les sources JS ne passent pas (comme tu es en pleine refonte de design je prefere te l’dire ;-) )

    A bientôt!

    Antoine

  23. Bruno Bichet
    Posted 11/08/2008 at 22:31 | Permalink

    @guiralantoine > yep, je corrige ça peu à peu quand je tombe sur les billets qui comportent des exemples de code. Avec plus de 230 billets en tout, ça prend du temps… Désolé ;)

  24. Posted 20/08/2008 at 02:17 | Permalink

    J’avoue que pour ma part, je préfère de loin faire confiance à un framework éprouvé comme jQuery qui permet en une ligne d’associer des fonctions d’événement à tous les éléments DOM que l’on souhaite. Bref, c’est un gain de temps des plus intéressants, quand on ne souhaite pas s’investir dans une R&D importante et que l’on est intéressé plus par le résultat que la manière.

    D’autres préféreront Prototype, voire des choses plus complètes comme Scriptaculous et autres MooTools.

  25. Bruno Bichet
    Posted 20/08/2008 at 02:45 | Permalink

    @Martin: A l’époque je ne connaissais pas jQuery et je ne sais même pas si ça existait ;) Depuis que j’ai découvert ce framework jQuery, je ne peux plus m’en passer.

    N’empêche que quand on n’est pas développeur, c’est quand même intéressant de connaitre les différentes strates qui nous ont amenés des événement onclick dans la balise aux comportement non obstrusifs…

    Je m’étais bien grillé quelques neurones pour comprendre et mettre en place la solution présentée dans ce billet ^^

    PS pour tous : comme j’ai rajouté Markdown Extra, j’ai plein de pétouilles à régler dans l’affichage des billets. J’y travaille ;)

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Subscribe without commenting