views:

12437

answers:

14

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);
A: 

Did you try:

    execBtn.setAttribute("onclick", function() { runCommand() });
Lark
that "shouldn't" work in IE6 / IE7 or IE8 in non-standards mode.For IE, you need to use: execBtn.onclick = function(){...}
scunliffe
+1  A: 

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).

Sietse
Can you add a code example of what you mean? Isn't this one of the 'bad ideas' above?
Peter Hilton
+1  A: 

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').

kch
+7  A: 

There is a LARGE collection of attributes you can't set in IE using .setAttribute() which includes every inline event handler.

See here for details:

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

scunliffe
+7  A: 

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.

Calvin_il
Short response and it worked great. Thanks for sharing.
Nip
button_element.onclick = function().. works in both IE and Firefox. For that matter it also works in Opera, Safari and Chrome. Any reason why setAttribute is needed (for Firefox)?
slebetman
The `onclick` way works fine in FF as well as IE. There is no reason ever to use the `setAttribute` version.
bobince
A: 

button_element.onclick = function() {doSomething();}; works on both IE (7.0) and FireFox (3.0) for me.. :-) Thanks!

A: 

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".

David Berger
A: 

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);
Marko
+2  A: 

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.

cdmckay
A: 

In some cases the examples listed here didn't work out for me in Internet Explorer.

Since you have to set the property with a method like this (without brackets)

HtmlElement.onclick = myMethod;

it won't work if you have to pass an object-name or even parameters. For the Internet Explorer you should create a new object in runtime:

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

Works also on other browsers.

This is a terrible way to pass parameters. It won't work for anything but the basic datatypes, and even then you need JSON-style escaping to turn them into literals. Always use an inline function expression (`onclick= function() { myMethod(someParameter); }`) instead of `new Function()`.
bobince
A: 

Thanks very much,

This is what I want.

A: 

I'm having a similar issue but I'm trying to SET the attribute. I need to change a textbox into a password text box. Works fine in FF etc. but not IE. It falls over when the following function is called:-

function clearPasswordBox(ID) {
clearTextBox(ID);
if(document.getElementById(ID).getAttribute('type')=='text' {
document.getElementById(ID).setAttribute('type','password');
}
document.getElementById(ID).focus();
}

Is there an IE work around?

Craig
Take a look at the bottom of my answer. To be compatible with IE you're going to have to make a new element and copy over the attributes. I found a nice function to do just that.
Acorn
A: 

This is an amazing function for cross-browser compatible event binding.

Got it from http://js.isite.net.au/snippets/addevent

With it you can just do Events.addEvent(element, event, function); and be worry free!

For example: (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);

Here's the function:

// 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};
})();

If you don't want to use such a big function, this should work for almost all browsers, including IE:

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

In response to Craig's question. You're going to have to make a new element and copy over the attributes of the old element. This function should do the job: (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;
}
Acorn
A: 

I'm having a similar problem .. this code works fine in IE but not in firefox, does anyone have a code i can paste to fix this issue?

<div onclick="document.location = 'http://www.njirishfootball.com/home/roster'  " style="cursor: pointer; width: 95px; height: 

40px; position: absolute; top: 57px; left: 397px;">

steve
Steve, please post a question of your own. This isn't a forum. Also, please pay attention to the formatting. It makes the reader's job that much easier.
George Marian
Why are you using a div with an onclick, heard of the anchor tag?
S Pangborn