Helpful Information
 
 
Category: DOM and JSON scripting
adding onclick handler

im creating a button dynamically on click of a button.
but the added onclick handler on the created button is not executed.
i've verified that the handler was added by looking thru the generated HTML using IE's document.documentElement.outerHTML. It's there but when the button is clicked the function showTxt() is not executed. If I save the generated code in a file and executes it, it runs OK.
What's the reason behind that?

here's the code:

function add(){
myDiv = document.getElementById("div");
obj = document.createElement("input");
obj.type = "button";
obj.name = "btnNew";
obj.id = "btn1";
obj.value = "New Row";
obj.onclick = "showTxt('test')";
myDiv.appendChild(obj);
//workaround below
//document.getElementById("btn1").onclick=function(){showTxt('test')};
}

function showTxt(txt){
alert(txt);
}

I've added a workaround which is commented above but just wondering why obj.onclick statement doesnt work.

try omitting the quotes:

obj.onclick = showTxt('test');

...

PLEASE NOTE: If the above still doesn't work, it's because normally when you register an event-handler this way (outside of a tag), JS syntax requires that the parentheses which normally indicate a function or a method be omitted. Example:

obj.onclick = showTxt

This would be correct and normally works, but in this particular case it raises the issue of how to pass the variable into the function then... I've wondered about this myself - hopefully somebody else here has an answer.

Hi,

The answer is normally to pass the data to the object on the constructor, store it in the new object, and then reference it whenever you need it:


<HTML><BODY>
<SCRIPT LANGUAGE="JavaScript">
<!--
but=0;
function add(what){
myDiv = document.getElementById("div");
obj = document.createElement("input");
obj.type = "button";
obj.name = "btnNew";
obj.id = "btn1";
obj.value = "New Row "+ ++but;
obj.text = what + but;
obj.onclick = showTxt;
myDiv.appendChild(obj);
}
function showTxt(){
alert(this.text);
}
//-->
</SCRIPT>
<A HREF="javascript:add('Text of your choice for button ')">add</A>
<div id="div">&nbsp;</div>
</BODY>
</HTML>


(with java script as javascript without the space)

tnx for your replies.
i just put the sample functions for the sake of simple illustration but the actual function (which has 3 arguments) to be added on the onclick handler is called by several functions and event handlers, so modifying the existing function is not the option. So maybe I'll stick with the workaround I implemented.
Tnx again, i appreciate your help :)

The problem is that .onclick and all other event handlers take a function reference ( onclick=showTxt; ) , not function call ( onclick=showTxt('abc') ). So you can't pass arguments. Event handlers always get one argument, an event object - except for in IE where there is no argument, since it has one global event object (window.event).

It's the same when you use event handlers in an HTML tag, as in

<a href="" onclick="showTxt('abc'); return false;">....</a>

What actually happens is that the browser creates an anonymous function that looks somewhat like this:

function onclick(event) {
showTxt('abc');
return false;
}

If you use a variable in the above:

<a href="" onclick="showTxt(myVar); return false;">....</a>

it looks for a global variable named "myVar."

function onclick(event) {
showTxt(myVar);
return false;
}

So if you need to pass different arguments to the event handler, you do what piglet suggested, assign them as properties to the object so you can reference them from that object using "this.myPropName".

obj.onclick = function(){showTxt('test')}

coxy :)

Hi coxy,

Yes - that was the workaround which they were trying not to use!


//workaround below
//document.getElementById("btn1").onclick=function(){showTxt('test')};

Since when is wrapping an HTML event handler function call in a Function object a 'workaround'? That's what the browser does, when you do the assignment in HTML....

I have the same problem, but what I did was slightly different:



//one of two ways
//#1
obj.onclick = tmpfnc
function tmpfnc () {
realthing (par1, par2, par3)
}
//#2
obj.onclick = realthing
function realthing () {
if (arguments.length != 0) {
//act on arguments, calling them as arguments[0], [1] and [2]
//respectively
/*dostuff*/
} else {
//assume arguments and act on that
/*dostuff*/
}
}


But that's assuming that all of your links use the same stuff...


Guardian
*just a thought*

it works now with this code:



function add(){
myDiv = document.getElementById("div");
obj = document.createElement("input");
obj.type = "button";
obj.name = "btnNew";
obj.value = "New Row";
obj.onclick = function(){showTxt('test')};
myDiv.appendChild(obj);
}

function showTxt(txt){
alert(txt);
}



Since when is wrapping an HTML event handler function call in a Function object a 'workaround'? That's what the browser does, when you do the assignment in HTML....

i consider

document.getElementById("btn1").onclick=function(){showTxt('test')};

as a "workaround" since instead of directly wrapping onclick handler to the object returned by document.createElement("input"), i have to put an id attribute and using

document.getElementById("btn1").onclick=function(){showTxt('test')};

ONLY after that created element has been appended to its parent element.

glenn...

Didn't recommend:

document.getElementById("btn1").onclick=function(){showTxt('test')};

..but coxy's terse:

obj.onclick = function(){showTxt('test')}

approach. Take a look in there:

<html>
<head>
<title>untitled</title>
</head>
<body>
<a href="#" onclick="alert('is this wrapped?')">test</a>
<script type="text/javascript" language="javascript">

alert(document.links[0].onclick);
alert(typeof document.links[0].onclick);

</script>
</body>
</html>

:D

didn't say you recommended it, i just explained why i called that solution a "workaround"

Oops, confused you with piglet - who compared the correct technique with what you had already termed (accurately) as a 'workaround'. cheers ;)

adios

WTF are you talking about adios?


...piglet - who compared the correct technique with what you had already termed (accurately) as a 'workaround'

I was comparing this from coxy:

obj.onclick = function(){showTxt('test')}


with this from glenngv

//workaround below
//document.getElementById("btn1").onclick=function(){showTxt('test')};


I was comparing the assignment of an anonymous function to the object with the assignment of an anonymous function to the object which glenngv called his 'workaround'.

I need to create a variable number of rows (with two data tags) in an html table, based on a variable evaluated in javascript code. The add() function given in this thread, somewhat solves this problem of mine, but not completely. As it can create a variable number of elements, but not variable number of rows in a table.

I am wondering if it is possible to create a variable number of rows with two data elements in an html table from a javascript function?

Thanks a lot in advance!

Of course, it is exactly the same idea -- just different code...



//tb is the tbody element of the table
//n is the number of rows
function addRows(tb, n) {
for(var i = 0; i < n; i++) {
var tr = document.createElement("<TR>");
var td1 = document.createElement("<TD>");
var td2 = document.createElement("<TD>");

//create something here to append to TD1/TD2

tr.appendChild(td1);
tr.appendChild(td2);

tb.appendChild(tr);
}
}


Hope that helps,
Sadiq.

Thanks a lot for the response! It certainly helped. I also found a great online resource to dynamically generate an HTML form:

http://www.pageresource.com/dhtml/ryan/part4-1.html

I am still having trouble in creating table rows dynamically. Here is the complete code:

************************************************

<HTML>
<HEAD>
</HEAD>
<BODY TOPMARGIN="1" LEFTMARGIN="1" MARGINWIDTH="0" MARGINHEIGHT="1" bgcolor="#ffffff">
<FORM NAME="MainForm" METHOD="post">
<div id="Table" style="position:absolute; left:5px; top:128px; height:20; width:964;">
<table width="964" border="0" cellpadding="10" cellspacing="1">
<table border="0" cellpadding="2" cellspacing="0">
<tr>
<td valign="top">
<span class="tabletitle">Market Briefing Mapping</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<table width="100%" border="0" cellpadding="4" cellspacing="1">
<TD><SELECT NAME="industryRepList" SIZE=6 multiple onChange='displayMappedTopics()'><OPTION VALUE="PTKIDFD~Baby Food" class="datacellT">001&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Babyfoods</OPTION><OPTION VALUE="PTROLLS~Bakery Products" class="datacellT2">002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Baked goods/bakery products</OPTION><OPTION VALUE="PTCKEE~Cookies" class="datacellT">003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cookies/biscuits and crackers</OPTION><OPTION VALUE="AGCEREAL~Cereals & Breakfast Food Industry" class="datacellT2">004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Breakfast cereals</OPTION><OPTION VALUE="AGDAIRY~Dairy Food Industry" class="datacellT">007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cheese</OPTION></SELECT></TD>
</table>
</span>
</td>
<td valign="top">
<span class="tabletitle">Mapped Topics</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<div id="showTopics" style="position:relative; top:5px; overflow:scroll; height:100; width:464; text-align:left;">
<table id="mappedTopicsTable" width="100%" border="0" cellpadding="4" cellspacing="1" class="tableborder">
</table>
</div>
</span>
</td>
</tr>
</table>
</table>
</div>
</FORM>
</BODY>
</HTML>
<SCRIPT>
<!--
var mktBriefingsToAdd = new Array();
var repNumsToAdd = new Array();
var mktBriefingsToDelete = new Array();

function getSelectedItem(listObject) {
var obj = new Object ();
for (var j = 0; j < listObject.options.length; j++) {
if (listObject.options[j].selected == true) {
obj.text = listObject.options[j].text;
obj.value = listObject.options[j].value;
break;
}
}
return obj;
}

function displayMappedTopics() {
var retObj = getSelectedItem(document.MainForm.industryRepList);
parseTopicData (retObj.value);
}

function parseTopicData(topicData) {
var arrTokensRec = topicData.split("|");
var rowelement, datatable, colelement, text;
datatable = document.getElementById("mappedTopicsTable");

for (var i=0; i < arrTokensRec.length; i++) {
var arrTokensCol = arrTokensRec[i].split("~");
rowelement = document.createElement("tr");
colelement = document.createElement("td");
alert ("arrTokensCol[0] : " + arrTokensCol[0]);
text = document.createTextNode(arrTokensCol[0]);
colelement.appendChild(text);
rowelement.appendChild(colelement);
//rowelement.innerHTML = "<td>arrTokensCol[0]</td>";
datatable.appendChild(rowelement);
alert ("datatable last child: " + document.getElementById("mappedTopicsTable").lastChild);
}
}
-->
</SCRIPT>
**************************************************

In the above code, there is a list box on left with some items in it. On the right side, is the table that I am trying to create dynamically, by clicking on an item on the left. When I click on an item in the list box on left, nothing happens. Is it because of the nested tables?

Any help will be greatly appreciated!

The most frustrating part of learning to play with DOM and creating tables that nobody told me was that you need to use TBODY tags.

I didn't see any in your posted code, and that is probably the main reason you don't see anything happening.

TBODY tags must encapsulate any TR tags you want your audience to see.

For example:


<table>
<tbody>
<tr>
<td>Some data</td>
</tr>
</tbody>
</table>


If you use HTML to create the above, ommitting the TBODY tags will not affect your output. However, if you use DOM to create the above, ommitting the TBODY tags will make your output disappear!

It's sort of bizzarre, and I'm not sure why it's not stressed more either in HTML or DOM more but that's the way it's been for me. If I hadn't scanned the web for nearly a day and wondered what the heck the TBODY tags were and why I kept seeing them, I never would have figured it out.

Hope that helps,
Sadiq.

I tried 'tbody' tag and to my astonishment, it works! Thanks so much for your help!! I wonder, why it's not in DOM documentation..

Regards,
Mamta.

'tbody' tag is in DOM documentation. But you are right, it's not clearly emphasized.










privacy (GDPR)