This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
If I create a whole lot of HTML elements using a loop, like
for (i= 1; i < 100; i++) {
var my_element = document.createElement ("td");
row.appendChild (my_element);
my_element.onclick = function () {my_function (i));
}
then when the element is clicked, the value of i passed to my_function is always 100, regardless of what number element is calling it. I have worked around this by using
my_element.id = "something"+i;
my_element.onclick = function (e) {my_function (e.target.id)};
(For Internet Explorer, the target needs to be srcElement, apparently.) I am curious to know whether there is any way to create the function without having to add the ID to the element like this.
The value of i changes with each iteration of the loop. You need a closure to capture the value of i:
(function(i) {
my_element.onclick = function () {my_function (i)};
}(i))
If you write a function which builds you a handler function, you can use the new scope which that gives you to ensure that you get the number you want. For example:
function BuildHandler (i) { return function () { alert(i); };
for (i= 1; i < 100; i++) {
var my_element = document.createElement ("td");
row.appendChild (my_element);
my_element.onclick = BuildHandler(i);
}
if I were you I will use Jquery (or prototype or whatever js frameworks that available)
on each elements you should add attributes like myid for example so that when you did on click you can retrive it.
for(i=1; i ++ ; i<100){
var myelement = "<td myid='something"+i+"' class='myTD'></td>" ;
row.append(myelement);
}
....
$(document).ready(function(){
$('.myTD').click(function(){
var id = $(this).attr('myid');
my_function(id);
});
});
I did this trick on my web app :)
Related
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
sorry for the title but I'm not sure what the correct terminology is for this issue. I am trying to dynamically generate a table of clickable elements using for loops in JavaScript. Each of the elements, when clicked, should trigger the same function but with different parameters. In my code I am setting the onClick function up like so:
elementArray[i].onClick = function() { clickFunction(i) };
However, when I do this the clickFunction is just taking whatever value i is currently set to, not what it was when I set the onClick function, which is what I want. Any ideas?
As I got your question you want a table having clickable element calling to same function with diff param. [Let me know if it's not your question]
So taking i (index or row no.) would be param to that function.
HTML :
<table id='myTable'></table>
Javascript :
for(i = 9; i >= 0; i--) {
var table = document.getElementById("myTable");
// Create an empty <tr> element and add it to the 1st position of the table:
var row = table.insertRow(0);
// Insert new cells (<td> elements) at the 1st and 2nd position of the "new" <tr> element:
var cell = row.insertCell(0);
// Add some text to the new cells:
cell.innerHTML = "<input type='button' onclick='callIt("+i+")'";
}
function callIt(index) {
alert(index);
}
I am considering that you want button to click.
Hope it will help you.
more you can get on w3schools
Here's a version of #Bhojendra Nepal's "duplicate question" applied to your question. With this HTML:
<div class="element-0">0</div>
<div class="element-1">1</div>
<div class="element-2">2</div>
And this script:
var elementArray = [];
var creatFunc = function($this,i){
return function() {
console.log(i);
$this.html(i + 1);
if (i>1) i++;
};
};
for (var i = 0; i < 3; i++) {
elementArray[i] = $('.element-' + i);
elementArray[i].click( creatFunc( elementArray[i] , i) );
}
by creating the functions in a separate function, we've isolated the variable. I added "if (i>1) i++;" to show how the new function keeps its own variable and can increment it (keep clicking on the third div to see the number keep increasing).
here's a jsfiddle:
https://jsfiddle.net/mckinleymedia/1cksb8ky/
I hope this helps.
Oh, I added jQuery to this. I'm not positive how to get this working in vanilla javascript off hand.
This question already has answers here:
Javascript multiple dynamic addEventListener created in for loop - passing parameters not working
(5 answers)
Closed 7 years ago.
Basically I created a bunch of cells and I am trying to add onclick to each one passing a variable to use inside the function. But doing straight up passes the 'i' variable as the last i value and not 0,1,2,3,4 etc. Here is a snippet of what I am doing.
for (var i = 0; i < cellCount.length; i++) {
var cellName= "cell"+ i
document.getElementById(cellName).onclick = function () { cellClicked(i) };
}
If you do not "capture" the value in a new scope, the callback will read the value from the actual i-counter.
Do something like this:
for (var i = 0; i < cellCount.length; i++) {
(function(copy_of_i) {
var cellName= "cell"+ i
document.getElementById(cellName).onclick = function () { cellClicked(copy_of_i) };
})(i)
}
Okay, I hope you don't all facepalm when you see this - I'm still finding my way around javascript.
I am putting together an RSVP form for a wedding website.
I want the guests to be able to add their names to the RSVP form, but only have as many fields showing as required. To this end, after each name field, there is a link to click, which will, when clicked, show a name field for the next guest.
The code below works... but I am sure it can be tidier.
I have tried to insert a for() loop into the code in several different ways, I can see that the for() loop increments correctly to the last value - but when it does so, it leaves only the last addEventListener in place. I can only assume, that I should be using a different kind of loop - or a different approach entirely.
How should I tidy up the following?
<script>
function showNextGuest(i) {
document.getElementsByTagName(\'fieldset\')[i].style.display = \'block\';
}
function initiateShowNextGuest() {
document.getElementsByTagName('fieldset')[0].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(1);},false);
document.getElementsByTagName('fieldset')[1].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(2);},false);
document.getElementsByTagName('fieldset')[2].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(3);},false);
document.getElementsByTagName('fieldset')[3].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(4);},false);
document.getElementsByTagName('fieldset')[4].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(5);},false);
}
window.onload = initiateShowNextGuest();
</script>
Your intuition is right - a for loop could indeed simplify it and so could a query selector:
var fieldsSet = document.querySelectorAll("fieldset"); // get all the field sets
var fieldss = [].slice.call(asSet); // convert the html selection to a JS array.
fields.map(function(field){
return field.querySelector("a"); // get the first link for the field
}).forEach(function(link, i){
// bind the event with the right index.
link.addEventListener("click", showNextGuest.bind(null, i+1), false);
});
This can be shortened to:
var links = document.querySelectorAll("fieldset a:first-of-type");
[].forEach.call(links, function(link, i){
link.addEventListener("click", showNextGuest.bind(null, i+1), false);
});
function nextGuest () {
for(var i = 0; i < 5; i++){
document.getElementsByTagName('fieldset')[i]
.getElementsByTagName('a')[0]
.addEventListener('click',function(){
showNextGuest(parseInt(i + 1));
}, false);
}
}
Benjamin's answer above is the best given, so I have accepted it.
Nevertheless, for the sake of completeness, I wanted to show the (simpler, if less elegant) solution I used in the end, so that future readers can compare and contrast between the code in the question and the code below:
<script>
var initiateShowNextGuest = [];
function showNextGuest(j) {
document.getElementsByTagName('fieldset')[j].style.display = 'block';
}
function initiateShowNextGuestFunction(i) {
return function() {
var j = i + 1;
document.getElementsByTagName('fieldset')[i].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(j);},false);
};
}
function initiateShowNextGuests() {
for (var i = 0; i < 5; i++) {
initiateShowNextGuest[i] = initiateShowNextGuestFunction(i);
initiateShowNextGuest[i]();
}
}
window.onload = initiateShowNextGuests();
</script>
In summary, the function initiateShowNextGuests() loops through (and then executes) initiateShowNextGuestFunction(i) 5 times, setting up the 5 anonymous functions which are manually written out in the code in the original question, while avoiding the closure-loop problem.
This question already has answers here:
How to use getElementsByClassName in javascript-function? [duplicate]
(3 answers)
Closed 8 years ago.
I have create the dynamic div and now trying to change the inner html of it but its not working please help me here is the code
function like(id)
{
var orgnldiv=document.getElementById(id);
var ndiv=document.createElement('DIV');
ndiv.id = 'like';
ndiv.className="likeclass";
var classname = document.getElementsByClassName("likeclass");
orgnldiv.appendChild(ndiv);
classname.innerHTML="example";
//alert(id);
}
Beware of the s in Elements. That means that you are getting a list rather than a single control.
Check How to use getElementsByClassName in javascript-function?
Use this:
function like(id)
{
var orgnldiv=document.getElementById(id);
var ndiv=document.createElement('DIV');
ndiv.id = 'like';
ndiv.className="likeclass";
orgnldiv.appendChild(ndiv);
var elements = document.getElementsByClassName("likeclass");
for(var i = 0; i < elements.length; i++) {
elements[i].innerHTML="example";
}
}
You get error because getElementsByClassName returns array of elements, not one elements. So you have to work with result like with array. If 1 element return loop will fire only 1 time. If 0 elements it wouldn't fire.
Hope this will help.
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
jQuery Looping and Attaching Click Events
(4 answers)
Closed 9 years ago.
I have function process_row that appends tags to html, and those tags are chained to a function upon clicked. (in this case, simply alert(i), its position in the result array).
But however, upon being clicked, the newly generated alerts the length of the entire result array. I have tried many, many changes to try and make it work, but it doesn't.
Strange thou, fab_div.attr("id", result_data[0]); works fine !! In Chrome inspect element the id tags are displayed as they are, but the click function points everything to the last element in the array.
for example, if I do, fab_div.click(function () { alert(result_data[0]) });, I get the name of the LAST element in the array, doesn't matter which element was clicked.
can anyone please explain to me... WHY??
I think it may have something to do with $("<div>") where JQuery thinks it's the same div that it's assigning to. Is there any way around this? The 's are generated dynamically and I would not want to let PHP do the echoing. Plus the content may be updated realtime.
Example dataset :
Smith_Jones#Smith#Jones#janet_Moore#Janet#Moore#Andrew_Wilson#Andrew#Wilson
After many, many changes, still not working:
function process_row(data){
result_array = data.split("#");
if(result_array.length > 0){
result_data =result_array[0].split("#");
for(i = 0; i < result_array.length; i++){
result_data =result_array[i].split("#");
var fab_text = result_data[1] + " " + result_data[2]
var fab_div = $("<div>");
fab_div.addClass('scroll_tap');
fab_div.attr("id", result_data[0]);
fab_div.append(fab_text)
// fab_div.click(function () { alert(i) });
// ^ not working, try appending list of id's to id_list
id_list.push(result_data[0])
$('#ls_admin').append(fab_div)
}
for(j = 0; j < id_list.length; j++){
$('#' + id_list[j]).click(function () { alert(j) })
}
}
}
Original Attempt:
function process_row(data){
result_array = data.split("#");
if(result_array.length > 0){
result_data =result_array[0].split("#");
for(i = 0; i < result_array.length; i++){
result_data =result_array[i].split("#");
var fab_text = result_data[1] + " " + result_data[2]
var fab_div = $("<div>").append(fab_text).click(function () { alert(i) });
fab_div.addClass('scroll_tap');
fab_div.attr("id", result_data[0]);
$('#ls_admin').append(fab_div)
}
}
}
If you must use an alert, then you can encapsulate the click handler in a self executing function and pass the index to it. Like,
(function (index) {
fab_div.click(function () {
alert(index);
});
})(i);
Although, this is not a clean way to do it. Otherwise, if you are looking to just manipulate the div element is any way, then adding any method directly will also work. Like,
fab_div.click(function () {
alert($(this).attr('id'));
});
You can refer a jsFiddle here
Wonky Solution, but it worked! Haha! Big thanks to Kevin B.
function process_row(data){
result_array = data.split("#");
if(result_array.length > 0){
result_data =result_array[0].split("#");
for(i = 0; i < result_array.length; i++){
result_data =result_array[i].split("#");
var fab_text = result_data[1] + " " + result_data[2]
var fab_div = $("<div>").append(fab_text);
fab_div.addClass('scroll_tap');
fab_div.attr("id", result_data[0]);
$('#ls_admin').append(fab_div)
}
$("#ls_admin").children(this).each(function( index ) {
$(this).append($(this).click(function () { alert($(this).text()) }));
});
}
}