Pourquoi une propriété onclick définie avec setAttribute ne fonctionne-t-elle pas dans IE?

StackOverflow https://stackoverflow.com/questions/95731

  •  01-07-2019
  •  | 
  •  

Question

Je suis tombé sur ce problème aujourd'hui, postant au cas où quelqu'un d'autre aurait le même problème.

var execBtn = document.createElement('input');
execBtn.setAttribute("type", "button");
execBtn.setAttribute("id", "execBtn");
execBtn.setAttribute("value", "Execute");
execBtn.setAttribute("onclick", "runCommand();");

Il s'avère que IE doit exécuter un onclick sur un élément généré dynamiquement. Nous ne pouvons pas utiliser setAttribute. Au lieu de cela, nous devons définir la propriété onclick sur l'objet avec une fonction anonyme enveloppant le code que nous voulons exécuter.

execBtn.onclick = function() { runCommand() };

Mauvaises idées:

Vous pouvez faire

execBtn.setAttribute("onclick", function() { runCommand() });

mais cela cèdera dans IE en mode non standard selon @scunliffe.

Vous ne pouvez pas faire cela du tout

execBtn.setAttribute("onclick", runCommand() ); 

car il s'exécute immédiatement et définit le résultat de runCommand () comme étant la valeur de l'attribut onClick, et vous ne pouvez pas le faire non plus

execBtn.setAttribute("onclick", runCommand);
Était-ce utile?

La solution

pour que cela fonctionne à la fois dans FF et dans IE, vous devez écrire dans les deux sens:


    button_element.setAttribute('onclick','doSomething();'); // for FF
    button_element.onclick = function() {doSomething();}; // for IE

merci à ce message .

MISE À JOUR : Ceci démontre que parfois il est nécessaire d’utiliser setAttribute! Cette méthode fonctionne si vous devez extraire l'attribut onclick d'origine du code HTML et l'ajouter à l'événement onclick afin qu'il ne soit pas remplacé:

// get old onclick attribute
var onclick = button_element.getAttribute("onclick");  

// if onclick is not a function, it's not IE7, so use setAttribute
if(typeof(onclick) != "function") { 
    button_element.setAttribute('onclick','doSomething();' + onclick); // for FF,IE8,Chrome

// if onclick is a function, use the IE7 method and call onclick() in the anonymous function
} else {
    button_element.onclick = function() { 
        doSomething();
        onclick();
    }; // for IE7
}

Autres conseils

Il existe une collection LARGE d'attributs que vous ne pouvez pas définir dans Internet Explorer avec .setAttribute () , qui inclut tous les gestionnaires d'événements en ligne.

Voir ici pour plus de détails:

http: //webbugtrack.blogspot. com / 2007/08 / bug-242-setattribute-doesnt-always-work.html

fonctionne très bien!

utiliser les deux méthodes semble être inutile maintenant:

execBtn.onclick = function() { runCommand() };

fonctionne apparemment dans tous les navigateurs actuels.

testé sous Firefox, IE, Safari, Opera, Chrome sous Windows; Firefox et Epiphany sur Ubuntu; non testé sur les systèmes Mac ou mobiles.

  • Craig: Je voudrais essayer & "document.getElementById (ID) .type = 'password';
  • Quelqu'un at-il vérifié le " AddEventListener " approche avec différents moteurs?

C’est une fonction extraordinaire pour la liaison d’événements compatible avec plusieurs navigateurs.

Vous l'avez obtenu de http://js.isite.net.au/snippets/addevent

Avec cela, vous pouvez simplement faire Events.addEvent(element, event, function); et être sans souci!

Par exemple: ( http://jsfiddle.net/Zxeka/ )

function hello() {
    alert('Hello');
}

var button = document.createElement('input');
button.value = "Hello";
button.type = "button";

Events.addEvent(input_0, "click", hello);

document.body.appendChild(button);

Voici la fonction:

// We create a function which is called immediately,
// returning the actual function object.  This allows us to
// work in a separate scope and only return the functions
// we require.
var Events = (function() {

  // For DOM2-compliant browsers.
  function addEventW3C(el, ev, f) {
    // Since IE only supports bubbling, for
    // compatibility we can't use capturing here.
    return el.addEventListener(ev, f, false);
  }

  function removeEventW3C(el, ev, f) {
    el.removeEventListener(ev, f, false);
  }

  // The function as required by IE.
  function addEventIE(el, ev, f) {
    // This is to work around a bug in IE whereby the
    // current element doesn't get passed as context.
    // We pass it via closure instead and set it as the
    // context using call().
    // This needs to be stored for removeEvent().
    // We also store the original wrapped function as a
    // property, _w.
    ((el._evts = el._evts || [])[el._evts.length]
        = function(e) { return f.call(el, e); })._w = f;

    // We prepend "on" to the event name.
    return el.attachEvent("on" + ev,
        el._evts[el._evts.length - 1]);
  }

  function removeEventIE(el, ev, f) {
    for (var evts = el._evts || [], i = evts.length; i--; )
      if (evts[i]._w === f)
        el.detachEvent("on" + ev, evts.splice(i, 1)[0]);
  }

  // A handler to call all events we've registered
  // on an element for legacy browsers.
  function addEventLegacyHandler(e) {
    var evts = this._evts[e.type];
    for (var i = 0; i < evts.length; ++i)
      if (!evts[i].call(this, e || event))
        return false;
  }

  // For older browsers.  We basically reimplement
  // attachEvent().
  function addEventLegacy(el, ev, f) {
    if (!el._evts)
      el._evts = {};

    if (!el._evts[ev])
      el._evts[ev] = [];

    el._evts[ev].push(f);

    return true;
  }

  function removeEventLegacy(el, ev, f) {
    // Loop through the handlers for this event type
    // and remove them if they match f.
    for (var evts = el._evts[ev] || [], i = evts.length; i--; )
      if (evts[i] === f)
        evts.splice(i, 1);
  }

  // Select the appropriate functions based on what's
  // available on the window object and return them.
  return window.addEventListener
      ? {addEvent: addEventW3C, removeEvent: removeEventW3C}
      : window.attachEvent
          ? {addEvent: addEventIE, removeEvent: removeEventIE}
          : {addEvent: addEventLegacy, removeEvent: removeEventLegacy};
})();

Si vous ne souhaitez pas utiliser une telle fonction, cela devrait fonctionner pour presque tous les navigateurs, y compris IE:

if (el.addEventListener) { 
    el.addEventListener('click', function, false); 
} else if (el.attachEvent) { 
    el.attachEvent('onclick', function); 
} 

En réponse à la question de Craig. Vous allez devoir créer un nouvel élément et copier les attributs de l'ancien. Cette fonction devrait faire le travail: ( source )

function changeInputType(oldObject, oType) {
  var newObject = document.createElement('input');
  newObject.type = oType;
  if(oldObject.size) newObject.size = oldObject.size;
  if(oldObject.value) newObject.value = oldObject.value;
  if(oldObject.name) newObject.name = oldObject.name;
  if(oldObject.id) newObject.id = oldObject.id;
  if(oldObject.className) newObject.className = oldObject.className;
  oldObject.parentNode.replaceChild(newObject,oldObject);
  return newObject;
}

Ou vous pouvez utiliser jQuery et éviter tous ces problèmes:

var execBtn = $("<input>", {
       type: "button",
       id: "execBtn",
       value: "Execute"
    })
    .click(runCommand);        

jQuery s’occupe également de tous les problèmes de navigation.

En fait, autant que je sache, les gestionnaires d’événements en ligne créés de manière dynamique fonctionnent parfaitement dans Internet Explorer 8 lorsqu’ils sont créés avec la commande x.setAttribute(); il vous suffit de les positionner correctement dans votre code JavaScript. Je suis tombé par hasard sur la solution à votre problème (et au mien) ici .

Lorsque j'ai déplacé toutes mes instructions contenant x.appendChild() à leurs positions correctes (c'est-à-dire, immédiatement après la dernière commande setAttribute au sein de leurs groupes), j'ai constaté que CHAQUE setAttribute fonctionnait dans IE8 comme il était supposé, y compris tous les formulaires attributs d'entrée (y compris & "nom &" et & "attributs de type &"; ainsi que mes & "onclick &"; gestionnaires d'événements).

J'ai trouvé cela assez remarquable, car tout ce que j'avais dans IE auparavant, c’était des ordures restituées sur l’écran, et une erreur après l’autre. En outre, j’ai constaté que chaque setAttribute fonctionnait toujours dans les autres navigateurs également. Par conséquent, si vous vous souvenez de cette simple pratique de codage, vous pourrez vous débrouiller dans la plupart des cas.

Cependant, cette solution ne fonctionnera pas si vous devez modifier des attributs à la volée, car ils ne peuvent pas être modifiés dans IE une fois que leur élément HTML a été ajouté au DOM. dans ce cas, j'imagine qu'il faudrait supprimer l'élément du DOM, puis le recréer, ainsi que ses attributs (dans le bon ordre, bien sûr!) pour qu'ils fonctionnent correctement et ne renvoyer aucune erreur.

Ecrivez la fonction en ligne et l'interprète est suffisamment intelligent pour savoir que vous écrivez une fonction. Faites-le comme ça, et ça suppose qu'il ne s'agit que d'une chaîne (ce qui est techniquement le cas).

function CheckBrowser(){
    if(navigator.userAgent.match(/Android/i)!=null||
        navigator.userAgent.match(/BlackBerry/i)!=null||
        navigator.userAgent.match(/iPhone|iPad|iPod/i)!=null||
        navigator.userAgent.match(/Nokia/i)!=null||
        navigator.userAgent.match(/Opera M/i)!=null||
        navigator.userAgent.match(/Chrome/i)!=null)
        {
            return 'OTHER';
    }else{
            return 'IE';
    }
}


function AddButt(i){
    var new_butt = document.createElement('input');
    new_butt.setAttribute('type','button');
    new_butt.setAttribute('value','Delete Item');
    new_butt.setAttribute('id', 'answer_del_'+i);
    if(CheckBrowser()=='IE'){
        new_butt.setAttribute("onclick", function() { DelElemAnswer(i) });
    }else{
        new_butt.setAttribute('onclick','javascript:DelElemAnswer('+i+');');
    }
}

Avez-vous essayé:

    execBtn.setAttribute("onclick", function() { runCommand() });

Dans certains cas, les exemples répertoriés ici ne fonctionnaient pas dans Internet Explorer.

Puisque vous devez définir la propriété avec une méthode comme celle-ci (sans crochets)

HtmlElement.onclick = myMethod;

cela ne fonctionnera pas si vous devez passer un nom d'objet ou même des paramètres. Pour Internet Explorer, vous devez créer un nouvel objet à l'exécution:

HtmlElement.onclick = new Function('myMethod(' + someParameter + ')');

Fonctionne également sur d'autres navigateurs.

Pas pertinent pour le problème onclick, mais aussi lié:

Pour les attributs HTML dont le nom est en conflit avec des mots réservés javascript, un autre nom est choisi, par exemple. <div class=''>, mais div.className, ou <label for='...'>, mais label.htmlFor.

Dans les navigateurs raisonnables, cela n’affecte pas setAttribute. Donc, dans gecko et webkit, vous appelez div.setAttribute('class', 'foo'), mais dans IE, vous devez utiliser le nom de la propriété javascript, donc div.setAttribute('className', 'foo').

Avez-vous envisagé d'écouter les événements plutôt que de définir l'attribut? Entre autres choses, il vous permet de passer des paramètres, ce qui était un problème que j'ai rencontré en essayant de le faire. Vous devez encore le faire deux fois pour IE et Mozilla:

function makeEvent(element, callback, param, event) {
    function local() {
        return callback(param);
    }

    if (element.addEventListener) {
        //Mozilla
        element.addEventListener(event,local,false);
    } else if (element.attachEvent) {
        //IE
        element.attachEvent("on"+event,local);
    }
}

makeEvent(execBtn, alert, "hey buddy, what's up?", "click");

Laissez simplement event être un nom comme & "; cliquez sur &"; ou " mouseover ".

Je l'ai fait pour contourner le problème et passer à autre chose. Dans mon cas, je n'utilise pas d'élément 'input', j'utilise plutôt une image lorsque j'ai essayé de définir l'option & "onclick &"; attribut pour cette image j'ai rencontré le même problème, alors j’ai essayé d’envelopper l’image avec un " un " élément et en faisant le point de référence à la fonction comme ceci.

var rowIndex = 1;
var linkDeleter = document.createElement('a');
linkDeleter.setAttribute('href', "javascript:function(" + rowIndex + ");");

var imgDeleter = document.createElement('img');
imgDeleter.setAttribute('alt', "Delete");
imgDeleter.setAttribute('src', "Imagenes/DeleteHS.png");
imgDeleter.setAttribute('border', "0");

linkDeleter.appendChild(imgDeleter);

Essayez ceci execBtn.onclick = function () {eval ('runCommand ()')};

Pour moi cela fonctionne.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top