RSS

Bug de la méthode getElementById dans IE6 : une solution !

mar, fév 24, 2009

JavaScript, Tips

La méthode getElementById(string) permet en Javascript d’obtenir l’élément avec l’id string si il est présent dans la page.
Malheureusement, dans certains cas cette fonction ne remplit pas son rôle sur IE6 et retourne des résultats non cohérents.
Heureusement il existe des solutions pour corriger ce bug !

Prenons l’exemple suivant, qui est une version simplifiée de ce que peut produire Zend_Form :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
    <head>
        <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
    </head>
    <body>
        <form id="frm" method="" action="">
            <p>
                <label for="my_input">Label</label>
                <input type="hidden" value="0" name="my_input"/>
                <input type="checkbox" value="1" id="my_input" name="my_input"/>
            </p>
        </form>
        <script type="text/javascript"><!--
           alert(document.getElementById('my_input').type);
       //--></script>
    </body>
</html>

Dans Firefox, Safari et les autres navigateurs évolués, aucun soucis, nous avons bien une alerte qui nous affiche checkbox. Par contre sous IE6, nous nous retrouvons avec un insolent hidden !

En effet, l’implémentation de getElementById dans IE6 comporte un bug qui fait qu’il ne fait pas uniquement la recherche sur l’attribut id mais également sur name et qu’il retourne donc le premier élément, ici le champ caché.

Dans notre cas, on pourrait simplement inverser l’ordre des champs et comme la case à cocher serait placée avant elle serait retournée. Mais nous pouvons également proposer une solution plus élégante et surtout plus générique pour contourner le problème : redéfinir la méthode.

Voici la nouvelle méthode :

if (/msie/i.test (navigator.userAgent))
    {
        document.nativeGetElementById = document.getElementById;
        document.getElementById = function(id)
        {
            // Get element using native method
            var elem = document.nativeGetElementById(id);
            if (elem)
            {
                // If id match, return element
                if (elem.attributes['id'].value == id)
                {
                    return elem;
                }
                // Otherwise look for the right one
                else
                {
                    for (var i = 1; i < document.all[id].length; i++)
                    {
                        if (document.all[id][i].attributes['id'].value == id)
                        {
                            return document.all[id][i];
                        }
                    }
                }
            }
            return null;
        }
    }

Explication du code :
- on ne redéfinit la fonction que pour Internet Explorer (on peut utiliser d’autre méthode de détection dans le premier if)
- on garde une copie de la fonction native de manière à pouvoir l’utiliser plus loin
- dans notre nouvelle méthode, on récupère l’élément avec l’ancienne méthode, puis on vérifie que son id correspond bien à ce que nous recherchons, si ce n’est pas le cas, on fait une recherche manuelle.

Exemple complet :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
    <head>
        <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
        <script type="text/javascript"><!--
           if (/msie/i.test (navigator.userAgent))
           {
               document.nativeGetElementById = document.getElementById;
               document.getElementById = function(id)
               {
                   // Get element using native method
                   var elem = document.nativeGetElementById(id);
                   if (elem)
                   {
                       // If id match, return element
                       if (elem.attributes['id'].value == id)
                       {
                           return elem;
                       }
                       // Otherwise look for the right one
                       else
                       {
                           for (var i = 1; i < document.all[id].length; i++)
                           {
                               if (document.all[id][i].attributes['id'].value == id)
                               {
                                   return document.all[id][i];
                               }
                           }
                       }
                   }
                   return null;
               }
           }
       //--></script>
    </head>
    <body>
        <form id="frm" method="" action="">
            <p>
                <label for="my_input">Label</label>
                <input type="hidden" value="0" name="my_input"/>
                <input type="checkbox" value="1" id="my_input" name="my_input"/>
            </p>
        </form>
        <script type="text/javascript"><!--
           alert(document.getElementById('my_input').type);
       //--></script>
    </body>
</html>

Référence : Sixteen Small Stones

Cet article a été écrit par :

Yann - a déjà écrit 3 article(s) sur Pims Labs.


Leave a Reply