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);
Source: Tips4all
to make this work in both FF and IE you must write both ways:
ReplyDeletebutton_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
}
There is a LARGE collection of attributes you can't set in IE using .setAttribute() which includes every inline event handler.
ReplyDeleteSee here for details:
http://webbugtrack.blogspot.com/2007/08/bug-242-setattribute-doesnt-always-work.html
Or you could use jQuery and avoid all those issues:
ReplyDeletevar execBtn = $("<input>", {
type: "button",
id: "execBtn",
value: "Execute"
})
.click(runCommand);
jQuery will take care of all the cross-browser issues as well.
This is an amazing function for cross-browser compatible event binding.
ReplyDeleteGot 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;
}
Did you try:
ReplyDeleteexecBtn.setAttribute("onclick", function() { runCommand() });
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).
ReplyDeleteNot relevant to the onclick issue, but also related:
ReplyDeleteFor 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').
I am using a single 'popup' in a page, and I use that for several controls to save bandwidth. (Stats: ASP.NET with ASP.NET AJAX) The panel is the same for each control, with the one exception of the postback info-- clicking a LinkButton in the shared panel should click a hidden, usercontrol-specific LinkButton elsewhere on the page.
ReplyDeleteWhen the user control is rolled over, I wanted to set the links in the shared panel to do the same postback as the links in the user control. This way, the correct item the link was clicked for can be captured in the page postback.
I was thinking in traditional terms when searching for my answer to: How do I register one LinkButton to click another?
I was trying to do the suggestions here, and the makeEvent() code was really great. This worked among all of my IE 8 tests, including IE 7 and quirks mode. It did not work in Firefox, Safari, or Chrome.
However, for those of temporarily confused by ASP.NET's references to things, a LinkButton is rendered as a link () with the href attribute set to do the postback, and only IE supports the 'onclick' event of an html link.
Instead of making a dynamic event listener for 'onclick,' I copied the href value. This works across all versions and modes of IE (7+), Firefox, Safari, and Chrome. (On Windows, anyway.)
Added as a reference for others who may be in the same mindset, and stumped as to why Internet Explorer supports onclick for links and Firefox does not.
button_element.onclick = function() {doSomething();};
ReplyDeleteworks on both IE (7.0) and FireFox (3.0) for me.. :-) Thanks!
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:
ReplyDeletefunction 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.
ReplyDeletevar 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);
In some cases the examples listed here didn't work out for me in Internet Explorer.
ReplyDeleteSince 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.
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:-
ReplyDeletefunction 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?
I am an experienced web programmer developing an add-on software for Mozilla for the first time.I searched through all comments posted by you all helpful guys.Ultimately nothing seemed to be working on Firefox 3.5.2 I was about to lose hope when I found this to be working:
ReplyDeleteSpanFavouriteRef.addEventListener("click", AddToFavourites, false);
AddToFavourites() function call worked.I still can't pass an argument,but I have found a work-around to that.
I got the idea from
http://ditio.net/2009/04/25/javascript-addeventlistener-method/
Thanks guys.Keep discussing....
works great!
ReplyDeleteusing 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?