JavaScript to add table row onclick events - javascript

I'm new to Javascript. I want to add onclick events to table rows. I'm not using JQuery.
I loop thru the rows and use a closure to make sure I have the state of the outer function for each row.
The looping works. Using alerts, I see the function being assigned for each iteration. But when I click the row, no alert is displayed.
Below is the HTML and code that can be loaded.
Why are the table row events not working?
<!doctype html>
<html lang="en">
<body>
<script>
function example4() {
var table = document.getElementById("tableid4");
var rows = table.getElementsByTagName("tr");
for (var i = 0; i < rows.length; i++) {
var curRow = table.rows[i];
//get cell data from first col of row
var cell = curRow.getElementsByTagName("td")[0];
curRow.onclick = function() {
return function() {
alert("row " + i + " data="+ cell.innerHTML);
};
};
}
}
function init() { example4(); }
window.onload = init;
</script>
<div>
Use loop to assign onclick handler for each table row in DOM. Uses Closure.
<table id="tableid4" border=1>
<tbody>
<tr><td>Item one</td></tr>
<tr><td>Item two</td></tr>
<tr><td>Item three</td></tr>
</tbody>
</table>
</div>
</body>
</html>

This seem to be the canonical way
DEMO
function example4() {
var table = document.getElementById("tableid4");
var rows = table.rows; // or table.getElementsByTagName("tr");
for (var i = 0; i < rows.length; i++) {
rows[i].onclick = (function() { // closure
var cnt = i; // save the counter to use in the function
return function() {
alert("row"+cnt+" data="+this.cells[0].innerHTML);
}
})(i);
}
}
window.onload = function() { example4(); }​
UPDATE: #ParkerSuperstar suggested that the i in (i) is not needed.
I have not tested this but his fiddle seems to work.

I'm not quite sure why you're using a closure here, could you be a bit more elaborate?
The reason you're not seeing the desired alert is because within the onclick function, you're returning another function. I.e:
window.onload = function() {
return function() {
alert("Closure... why?");
};
};
Something like this won't really work because you're never calling the nested function... try it without using the closure, or comment explaining why you want a closure because you're explanation didn't make much sense to me.

You just have to remove an extra function and script will be like this
<script>
function example4() {
var table = document.getElementById("tableid4");
cells = table.getElementsByTagName('td');
for (var i=0,len=cells.length; i<len; i++){
cells[i].onclick = function(){
alert(this.innerHTML);
}
}
}
function init() { example4(); }
window.onload = init;
</script>

Related

How can I bind events to dynamically added textbox?

I am dynamically creating table rows and adding text boxes.
I added new row and added a event listener to it.
I also tried creating a cell and adding event listener to it.
I am using a Javascript function for this, but my function is invoked even before the
event is triggered from newly created html element.
In all cases the function is called as soon as dynamic element is created
Any help is appreciated.
Doesn't Work:
Try 1
function addnewrow()
{
var row = table.insertRow(x.rowIndex+1);
row.addEventListener("click", addme, false);
}
function addme()
{
alert("am called ");
}
Try 2
var t12=document.createElement("input");
t12.id = index+"q";
t12.name = index+"q";
cellnewrow2.appendChild(t12);
//cellnewrow2.addEventListener("click",addme(),false);
cellnewrow2.onclick =addme();
Your first example is actually correct. May be there are other ways for your question. But you can also use bindand refer your arguments or parameters with thiskeyword inside the function.
function addnewrow() {
var table = document.getElementById('tbl');
var row = table.insertRow(1);
row.innerHTML = "CLICK ME";
let arg = 1;
row.addEventListener("click", addme.bind(arg));
}
function addme() {
alert("am called with the argument: " + this);
}
addnewrow();
<table id="tbl">
<tr>
<td>Hello</td>
</tr>
</table>
You can't implement a function when you want it to be a callback function. With not considering the performance optimizing, it could be the very basic code for you as practice.
<html>
<body>
<button id='btn'>Click Me</button>
<div id='div'></div>
</body>
<script>
var count = 0;
var btn = document.getElementById('btn');
btn.addEventListener('click', function(){
var div = document.getElementById('div');
div.innerHTML += '<h2>' + count + '</h2>';
count++;
});
</script>
</html>

Generate a function for an event

I want to generate functions for an event by using a loop. Surely in the example below, when pressing the button, it will gives the value 100 and not 1.
<body>
<button id="b1">klickMeNow</button>
<script>
var i=1;
document.getElementById("b1").addEventListener("click", function() { alert(i);}, false);
var i=100;
</script>
</body>
I came up with this solution using a generate function:
<button id="b1">klickMeNow</button>
<script>
var i=1;
document.getElementById("b1").addEventListener("click", generate(i), false);
var i=100;
function generate(i1) {
f = function () {alert(i1);};
return f;
}
</script>
Is there a more elegant solution without writing a generate function?
Are you looking to for a simple counting function?
var count = (function() {
var c = 0;
return function() {
return ++c;
}
}());
document.getElementById('b1').onclick = function() {
alert(count());
}
<button id="b1">Click Me</button>
Oh sorry for the confusion.
If you run the first snippet it gives 100 as a result, but I want that it prints 1, the actual value when I bind the function.

Non-independence of two javascript scripts

He Guys,
I have two scripts that work fine separately. One is for loading images and one is for loading Youtube iframe embeds.
However they don't seem to work together. Could you help out?
<iframe width="560" height="315" frameborder="0" data-src="https://www.youtube.com/embed/fKnbOJ4NAvS" src=""></iframe>
<a rel="nofollow" target="_blank" href="https://plus.google.com/share?url=https%3A%2F%2Fwww.domain.com"><img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="googleplus.png"></a>
<script>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
} } }
window.onload = init;
</script>
<script>
function init() {
var vidDefer = document.getElementsByTagName('iframe');
for (var i=0; i<vidDefer.length; i++) {
if(vidDefer[i].getAttribute('data-src')) {
vidDefer[i].setAttribute('src',vidDefer[i].getAttribute('data-src'));
} } }
window.onload = init;
</script>
You have made a couple of invalid assumptions.
Firstly, all scripts occupy the same global name space. Multiple <script>...</script> tags are not independent, therefore.
<script>
//script 1
</script>
<script>
//script 2
</script>
is equivalent to :
<script>
//script 1
//script 2
</script>
Secondly, repeated assignments of functions to window.onload are not cumulative. With window.onload = init followed by a second window.onload = init, the second assignment will override the first.
Now you should understand that your second script nullifies the first.
To fix, you could give the two functions unique names, and call them from a single (anonymous) window.onload handler :
<script>
function init_1() {
var imgElements = document.getElementsByTagName('img');
for (var i=0; i<imgElements.length; i++) {
if(imgElements[i].getAttribute('data-src')) {
imgElements[i].setAttribute('src', imgElements[i].getAttribute('data-src'));
}
}
}
function init_2() {
var vidElements = document.getElementsByTagName('iframe');
for (var i=0; i<vidElements.length; i++) {
if(vidElements[i].getAttribute('data-src')) {
vidElements[i].setAttribute('src', vidElements[i].getAttribute('data-src'));
}
}
}
window.onload = function() {
init_1();
init_2();
};
</script>
You could alternatively omit init_1() and init_2(), and write everything direcly inside an anonymous window.onload handler :
<script>
window.onload = function() {
var imgElements = document.getElementsByTagName('img');
var vidElements = document.getElementsByTagName('iframe');
var i;
for (i=0; i<imgElements.length; i++) {
if(imgElements[i].getAttribute('data-src')) {
imgElements[i].setAttribute('src', imgElements[i].getAttribute('data-src'));
}
}
for (i=0; i<vidElements.length; i++) {
if(vidElements[i].getAttribute('data-src')) {
vidElements[i].setAttribute('src', vidElements[i].getAttribute('data-src'));
}
}
};
</script>
It is perfectly OK to reuse the variable i in this way.
You will notice that I renamed you variables to avoid "Defer", which has a very specific meaning in JavaScript.

Issue adding event with addEventListener to Input in documentFragment

I am creating a div using createDocumentFragment(). In the Div is a table with a list of input. When you click on any of the checkboxes I want to trigger the alert('Yes'). when I add the event it does not add it to the input but with Firefox it seems to call the alert when it is added to the table.
Can someone explain what I am doing wrong?
function deptFilter(rPattern)
{
var lclData = JSON.parse(rPattern);
var loc = document.getElementById('show2');
var arrayKeys = Object.keys(lclData);
var outputData;
var LCL_List
var LCLTables;
var LCLtd;
var LCLtr;
var LCLInput;
var LCLDiv;
var LCL_List = document.createDocumentFragment(document.createElement('DIV'));
LCL_List.id = 'LCLTable';
for(var x = 0; x < arrayKeys.length; x++)
{
LCLDiv = LCL_List.appendChild(document.createElement('DIV'));
LCLTables = LCLDiv.appendChild(document.createElement('TABLE'));
for(var y = 0; y < lclData[arrayKeys[x]].length; y++)
{
LCLtr = LCLTables.appendChild(document.createElement('TR'));
LCLtd = LCLtr.appendChild(document.createElement('TD'));
LCLInput = LCLtd.appendChild(document.createElement('INPUT'));
LCLInput.id = lclData[arrayKeys[x]][y]['Name'];
LCLInput.type='checkbox';
LCLInput.addEventListener("click", alert("Yes"));
}
}
loc.appendChild(LCL_List);
}
When you install an event handler like this:
LCLInput.addEventListener("click", alert("Yes"));
You're executing alert() immediately and then passing the return value from that to addEventListener(). This is obviously NOT what you want. Instead, you need to pass a function reference to addEventListener and that function will then call your alert() sometime later:
LCLInput.addEventListener("click", function(e) {
alert("Yes");
});
Or you can define a named function and pass just its name:
function handleClick(e) {
alert("Yes");
}
LCLInput.addEventListener("click", handleClick);
This is the way to add event listner:
LCLInput.addEventListener("click", function() {
alert("Yes");
});

Failure in changing node content + JavaScript

I wrote this code for create menu with div tag
HTML:
<div id="firstMenuList">
<div id="firstMenu">choose▼</div>
<div id="menulist" class="menulist"></div>
</div>
JavaScript:
<script>
function ccc() {
var id="firstMenu";
var ar=new Array("hi","there","hello","world");
var node=document.createElement("div");
var parent=document.getElementById("menulist");
var nodeData="";
for (var i=0;i<ar.length;i++)
{
var node=document.createElement("div");
node.setAttribute("id",id+""+i);
node.setAttribute("class","menulist");
node.setAttribute("onclick","select("+id+""+i+")");
node.style.top=((i+1)*100)+3+"%";
node.innerHTML=ar[i];
parent.appendChild(node);
}
}
function select(id)
{
var p=document.getElementById(id);<-this doesn't work on elements that created dynamically
p.style.backgroundColor="red";
var t = p.innerHTML;
}
</script>
This code creates the menu, but when I click on the menu items code breaks.
The error is:
"parent is null"
To pass the id to the function you need to ensure that you put quotes around the id:
node.setAttribute("onclick","select('"+id+i+"')");
// note the single quotes ----------^--------^
Demo: http://jsfiddle.net/QK5Wh/1/
But you don't need to use the id to get the element when you can pass a direct reference to the element itself:
node.setAttribute("onclick","select(this)");
And then:
function select(p) {
p.style.backgroundColor="red";
var t = p.innerHTML;
}
Demo: http://jsfiddle.net/QK5Wh/
I'll suggest to avoid the inline event binding. Here is a working example:
http://jsfiddle.net/H4S2f/1/
function ccc() {
var id="firstMenu";
var cls="firstMenuList";
var ar=new Array("hi","there","hello","world");
var node=document.createElement("div");
var parent=document.getElementById("menulist");
var nodeData="";
for (var i=0;i<ar.length;i++)
{
var node=document.createElement("div");
node.setAttribute("id",id+""+i);
node.setAttribute("class","menulist");
(function(i) {
node.addEventListener("click", function() {
select(id+""+i)
});
})(i);
node.style.top=((i+1)*100)+3+"%";
node.innerHTML=ar[i];
parent.appendChild(node);
}
}
function select(id)
{
var p=document.getElementById(id);
p.style.backgroundColor="red";
var t = p.innerHTML;
}
ccc();

Categories