Why does an onclick property set with setAttribute fail to work in IE?

Viewed 187842

Ran into this problem today, posting in case someone else has the same issue.

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

Turns out to get IE to run an onclick on a dynamically generated element, we can't use setAttribute. Instead, we need to set the onclick property on the object with an anonymous function wrapping the code we want to run.

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

BAD IDEAS:

You can do

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

but it will break in IE in non-standards mode according to @scunliffe.

You can't do this at all

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

because it executes immediately, and sets the result of runCommand() to be the onClick attribute value, nor can you do

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

to make this work in both FF and IE you must write both ways:


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

thanks to this post.

UPDATE: This is to demonstrate that sometimes it is necessary to use setAttribute! This method works if you need to take the original onclick attribute from the HTML and add it to the onclick event, so that it doesn't get overridden:

// 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
}

works great!

using both ways seem to be unnecessary now:

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

apparently works in every current browser.

tested in current Firefox, IE, Safari, Opera, Chrome on Windows; Firefox and Epiphany on Ubuntu; not tested on Mac or mobile systems.

  • Craig: I'd try "document.getElementById(ID).type='password';
  • Has anyone checked the "AddEventListener" approach with different engines?

Or you could use jQuery and avoid all those issues:

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

jQuery will take care of all the cross-browser issues as well.

Write the function inline, and the interpreter is smart enough to know you're writing a function. Do it like this, and it assumes it's just a string (which it technically is).

Did you try:

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

Not relevant to the onclick issue, but also related:

For html attributes whose name collide with javascript reserved words, an alternate name is chosen, eg. <div class=''>, but div.className, or <label for='...'>, but label.htmlFor.

In reasonable browsers, this doesn't affect setAttribute. So in gecko and webkit you'd call div.setAttribute('class', 'foo'), but in IE you have to use the javascript property name instead, so div.setAttribute('className', 'foo').

Have you considered an event listener rather than setting the attribute? Among other things, it lets you pass parameters, which was a problem I ran into when trying to do this. You still have to do it twice for IE and 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");

Just let event be a name like "click" or "mouseover".

I did this to get around it and move on, in my case I'm not using an 'input' element, instead I use an image, when I tried setting the "onclick" attribute for this image I experienced the same problem, so I tried wrapping the image with an "a" element and making the reference point to the function like this.

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);
Related