I'm having several div's #mydiv1, #mydiv2, #mydiv3, ... and want to assign click handlers to them:
$(document).ready(function(){
for(var i = 0; i < 20; i++) {
$('#question' + i).click( function(){
alert('you clicked ' + i);
});
}
});
But instead of showing 'you clicked 3' when click on #mydiv3 (as for every other click) I get 'you clicked 20'. What am I doing wrong?
It's a common mistake to create closures in loops in Javascript. You need to have some sort of callback function like this:
function createCallback( i ){
return function(){
alert('you clicked' + i);
}
}
$(document).ready(function(){
for(var i = 0; i < 20; i++) {
$('#question' + i).click( createCallback( i ) );
}
});
Update June 3, 2016: since this question is still getting some traction and ES6 is getting popular as well, I would suggest a modern solution. If you write ES6, you can use the let keyword, which makes the i variable local to the loop instead of global:
for(let i = 0; i < 20; i++) {
$('#question' + i).click( function(){
alert('you clicked ' + i);
});
}
It's shorter and easier to understand.
To clarify, i is equal to 20 because the click event won't have fired until after the loop has finished.
$(document).ready(function(){
for(var i = 0; i < 5; i++) {
var $li= $('<li>' + i +'</li>');
(function(i) {
$li.click( function(){
alert('you clicked ' + i);
});
}(i));
$('#ul').append($li);
}
});
Using on to attach the 'click' handler you can use the event data in order to pass your data like in:
for(var i = 0; i < 20; i++) {
$('#question' + i).on('click', {'idx': i}, function(e) {
alert('you clicked ' + e.data.idx);
});
}
//
// let's creat 20 buttons
//
for(var j = 0; j < 20; j++) {
$('body').append($('<button/>', {type: 'button', id: 'question' + j, text: 'Click Me ' + j}))
}
//
// Passing data to the handler
//
for(var i = 0; i < 20; i++) {
$('#question' + i).on('click', {'idx': i}, function(e) {
console.log('you clicked ' + e.data.idx);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can get by with assigning the click handler once (or at least not making many unnecessary closures). Put all the divs in one class mydivs, then:
$(document).ready(function(){
$('.mydivs').click(function(){
// Get the number starting from the ID's 6th character
// This assumes that the common prefix is "mydiv"
var i = Number(this.id.slice(5));
alert('you clicked ' + i);
});
});
This looks at the element's ID to get its number, using the slice string method to strip the initial letters off.
Note: It may be better to use
$('#divcontainer').on('click', '.mydivs', function(){
instead of
$('.mydivs').click(function(){
Generally, if you are looking to assign click handles to a large number of items, you want to have a container (higher level div) that interprets the clicks for you, as the click bubbles up from the dom.
<div id="bucket">
<span class="decorator-class" value="3">
...
</div>
<script>
$(document).ready(function(e){
$("#bucket").live('click', function(){
if(e.target).is('span'){
alert("elementid: " + $(e.target).val());
}
}
}
<script>
Related
I'm having several div's #mydiv1, #mydiv2, #mydiv3, ... and want to assign click handlers to them:
$(document).ready(function(){
for(var i = 0; i < 20; i++) {
$('#question' + i).click( function(){
alert('you clicked ' + i);
});
}
});
But instead of showing 'you clicked 3' when click on #mydiv3 (as for every other click) I get 'you clicked 20'. What am I doing wrong?
It's a common mistake to create closures in loops in Javascript. You need to have some sort of callback function like this:
function createCallback( i ){
return function(){
alert('you clicked' + i);
}
}
$(document).ready(function(){
for(var i = 0; i < 20; i++) {
$('#question' + i).click( createCallback( i ) );
}
});
Update June 3, 2016: since this question is still getting some traction and ES6 is getting popular as well, I would suggest a modern solution. If you write ES6, you can use the let keyword, which makes the i variable local to the loop instead of global:
for(let i = 0; i < 20; i++) {
$('#question' + i).click( function(){
alert('you clicked ' + i);
});
}
It's shorter and easier to understand.
To clarify, i is equal to 20 because the click event won't have fired until after the loop has finished.
$(document).ready(function(){
for(var i = 0; i < 5; i++) {
var $li= $('<li>' + i +'</li>');
(function(i) {
$li.click( function(){
alert('you clicked ' + i);
});
}(i));
$('#ul').append($li);
}
});
Using on to attach the 'click' handler you can use the event data in order to pass your data like in:
for(var i = 0; i < 20; i++) {
$('#question' + i).on('click', {'idx': i}, function(e) {
alert('you clicked ' + e.data.idx);
});
}
//
// let's creat 20 buttons
//
for(var j = 0; j < 20; j++) {
$('body').append($('<button/>', {type: 'button', id: 'question' + j, text: 'Click Me ' + j}))
}
//
// Passing data to the handler
//
for(var i = 0; i < 20; i++) {
$('#question' + i).on('click', {'idx': i}, function(e) {
console.log('you clicked ' + e.data.idx);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can get by with assigning the click handler once (or at least not making many unnecessary closures). Put all the divs in one class mydivs, then:
$(document).ready(function(){
$('.mydivs').click(function(){
// Get the number starting from the ID's 6th character
// This assumes that the common prefix is "mydiv"
var i = Number(this.id.slice(5));
alert('you clicked ' + i);
});
});
This looks at the element's ID to get its number, using the slice string method to strip the initial letters off.
Note: It may be better to use
$('#divcontainer').on('click', '.mydivs', function(){
instead of
$('.mydivs').click(function(){
Generally, if you are looking to assign click handles to a large number of items, you want to have a container (higher level div) that interprets the clicks for you, as the click bubbles up from the dom.
<div id="bucket">
<span class="decorator-class" value="3">
...
</div>
<script>
$(document).ready(function(e){
$("#bucket").live('click', function(){
if(e.target).is('span'){
alert("elementid: " + $(e.target).val());
}
}
}
<script>
I'm having several div's #mydiv1, #mydiv2, #mydiv3, ... and want to assign click handlers to them:
$(document).ready(function(){
for(var i = 0; i < 20; i++) {
$('#question' + i).click( function(){
alert('you clicked ' + i);
});
}
});
But instead of showing 'you clicked 3' when click on #mydiv3 (as for every other click) I get 'you clicked 20'. What am I doing wrong?
It's a common mistake to create closures in loops in Javascript. You need to have some sort of callback function like this:
function createCallback( i ){
return function(){
alert('you clicked' + i);
}
}
$(document).ready(function(){
for(var i = 0; i < 20; i++) {
$('#question' + i).click( createCallback( i ) );
}
});
Update June 3, 2016: since this question is still getting some traction and ES6 is getting popular as well, I would suggest a modern solution. If you write ES6, you can use the let keyword, which makes the i variable local to the loop instead of global:
for(let i = 0; i < 20; i++) {
$('#question' + i).click( function(){
alert('you clicked ' + i);
});
}
It's shorter and easier to understand.
To clarify, i is equal to 20 because the click event won't have fired until after the loop has finished.
$(document).ready(function(){
for(var i = 0; i < 5; i++) {
var $li= $('<li>' + i +'</li>');
(function(i) {
$li.click( function(){
alert('you clicked ' + i);
});
}(i));
$('#ul').append($li);
}
});
Using on to attach the 'click' handler you can use the event data in order to pass your data like in:
for(var i = 0; i < 20; i++) {
$('#question' + i).on('click', {'idx': i}, function(e) {
alert('you clicked ' + e.data.idx);
});
}
//
// let's creat 20 buttons
//
for(var j = 0; j < 20; j++) {
$('body').append($('<button/>', {type: 'button', id: 'question' + j, text: 'Click Me ' + j}))
}
//
// Passing data to the handler
//
for(var i = 0; i < 20; i++) {
$('#question' + i).on('click', {'idx': i}, function(e) {
console.log('you clicked ' + e.data.idx);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can get by with assigning the click handler once (or at least not making many unnecessary closures). Put all the divs in one class mydivs, then:
$(document).ready(function(){
$('.mydivs').click(function(){
// Get the number starting from the ID's 6th character
// This assumes that the common prefix is "mydiv"
var i = Number(this.id.slice(5));
alert('you clicked ' + i);
});
});
This looks at the element's ID to get its number, using the slice string method to strip the initial letters off.
Note: It may be better to use
$('#divcontainer').on('click', '.mydivs', function(){
instead of
$('.mydivs').click(function(){
Generally, if you are looking to assign click handles to a large number of items, you want to have a container (higher level div) that interprets the clicks for you, as the click bubbles up from the dom.
<div id="bucket">
<span class="decorator-class" value="3">
...
</div>
<script>
$(document).ready(function(e){
$("#bucket").live('click', function(){
if(e.target).is('span'){
alert("elementid: " + $(e.target).val());
}
}
}
<script>
I'm creating a bunch of elements with a generic onclick event like
function foo( i , j ) {
alert("foo");
//dostuff
};
for (i = 1; i < 8; i++){
var clas = get_class_for_index( i );
for ( j = 0; j < 96; j++){
// tbody > #(i) is a <tr>
$("#table > tbody > #" + i ).append( function(){
// I want to give ( i , j ) to foo
return $("<td id='" + j + "' class='" + clas + "'></td>").on("click", foo );
});
};
};
So, how could I give these arguments to foo? I could also use the IDs of and due they're (i,j) but how do I get them from inside foo?
You need to use closure with IIFE here, otherwise because of the scoping you will end up passing the last iterated value of i or j to the event handler.
Something like this:
var $anchors = $("a");
function foo(idx) {
alert("foo " + idx);
};
for(var i = 0; i < $anchors.length; i++) {
$anchors.eq(i).on("click", (function(i) {
return function(e) {
foo(i);
}
}(i)));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Link | Link | Link | Link
In the above example, we are using a function that is immediately executed (with i as a parameter) and returns a function which will then be bound as the click handler and pass the correct i to your foo. This is called an IIFE (immediately-inoked function expression).
Can I pass parameters to event Handler?
No you cant. The event handler function executes when the event occurs, You are not calling foo() to pass i and j, foo() will get executed even after for loop execution finishes and there will not be any existence of i & j.
Then What can I do in my condition.
The best way is add i and j values to DOM element itself so you can access it in event handler function. You can use data() method of jQuery to add extra information to DOM.
function foo(evt) {
$(evt.currentTarget).data() //You will get here all values, i.e. i & j
//dostuff
};
for (i = 1; i < 8; i++) {
var clas = get_class_for_index(i);
for (j = 0; j < 96; j++) {
// tbody > #(i) is a <tr>
$("#table > tbody > #" + i).append(function() {
// I want to give ( i , j ) to foo
return $("<td id='" + j + "' class='" + clas + "'></td>").data({
i: i,
j: j
}).on("click", foo);
});
};
};
Here is updated fiddle.
You need to use jquery on function in order to register the event to the element once created, you can use the Id of the element to attach the event to it and call the foo in the event callback function.
I have added a working snipped that used a combined id with i and j as follows
function foo( i , j ) {
console.log(i+"_"+j);
alert(i+"_"+j);
//dostuff
};
for (i = 1; i < 8; i++){
var clas = "aa_"+i;
$("#table").append("<tr id='" + i + "'></tr>");
for ( j = 0; j < 96; j++){
// tbody > #(i) is a <tr>
$("#table > tbody > #" + i ).append( function(){
// I want to give ( i , j ) to foo
return $("<td id='test_" + i + "_" + j + "' class='" + clas + "'>aa</td>").on("click", function(){
var id = $(this).attr("id").split('_');
//console.log(id);
foo(id[1],id[2]);
} );
});
};
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="table"></table>
When using event handler you may use .on() of jquery for the event handler like this example.
$("#id").on("click", function(){
//do stuff here or call a function;
});
Reference: http://api.jquery.com/on/
I have a question about the .click function in Jquery. I have this code:
for (var i = 0; i < 5; i++) {
var divTest = $('<div></div>');
divTest.text("My Div " + i);
divTest.click(function() {
alert("Alert: Div " + i);
});
$('#myTest').append(divTest);
}
I expected to add five divs to the "myTest" element and for each div the onclick function would show an alert with the corresponding div number.
The divs were added properly, but when I click on the divs I always get the alert with the text: "Alert: Div 5". Why? What I have to change to generate the behavior that I'm expecting?
Here is my jsFiddle: http://jsfiddle.net/BKFGm/2/
In this case you should use closure:
(function(i) {
divTest.click(function() {
alert("Div: " + i);
});
})(i);
DEMO: http://jsfiddle.net/BKFGm/4/
Another option is to pass i in the eventData map:
divTest.click({ i: i }, function(e) {
alert("Div: " + e.data.i);
});
DEMO: http://jsfiddle.net/BKFGm/11/
Once again, a classic case of closures. i keeps getting incremented, whereas you want to anchor it in the click event. Try this:
for( i=0; i<5; i++) {
(function(i) {
// your code that depends on `i` here
})(i);
}
This is a scope issue. Also, it's a very commonly asked question here.
The simple fix:
for(var i = 0; i < 5; i++){
var divTest = $('<div></div>')
divTest .text("My Div " + i);
(function(index){
divTest .click(function () {
alert("Div: " + index);
});
})(i);
$('#myTest').append(divTest);
}
When the Alert happens, the variable i is already set to 5.
.click works in a different scope than your cycle and it is undefined when your click handler is executed, unless you have an other i variable on the global scope.
You can also try this
$(function() {
for(var i = 0; i < 5; i++){
var divTest = $('<div/>', {
'text':"My Div " + i,
'click':(function(i){
return function(){
alert("Div: " + i);
}
})(i)
});
$('#myTest').append(divTest);
}
});
DEMO.
I'm having several div's #mydiv1, #mydiv2, #mydiv3, ... and want to assign click handlers to them:
$(document).ready(function(){
for(var i = 0; i < 20; i++) {
$('#question' + i).click( function(){
alert('you clicked ' + i);
});
}
});
But instead of showing 'you clicked 3' when click on #mydiv3 (as for every other click) I get 'you clicked 20'. What am I doing wrong?
It's a common mistake to create closures in loops in Javascript. You need to have some sort of callback function like this:
function createCallback( i ){
return function(){
alert('you clicked' + i);
}
}
$(document).ready(function(){
for(var i = 0; i < 20; i++) {
$('#question' + i).click( createCallback( i ) );
}
});
Update June 3, 2016: since this question is still getting some traction and ES6 is getting popular as well, I would suggest a modern solution. If you write ES6, you can use the let keyword, which makes the i variable local to the loop instead of global:
for(let i = 0; i < 20; i++) {
$('#question' + i).click( function(){
alert('you clicked ' + i);
});
}
It's shorter and easier to understand.
To clarify, i is equal to 20 because the click event won't have fired until after the loop has finished.
$(document).ready(function(){
for(var i = 0; i < 5; i++) {
var $li= $('<li>' + i +'</li>');
(function(i) {
$li.click( function(){
alert('you clicked ' + i);
});
}(i));
$('#ul').append($li);
}
});
Using on to attach the 'click' handler you can use the event data in order to pass your data like in:
for(var i = 0; i < 20; i++) {
$('#question' + i).on('click', {'idx': i}, function(e) {
alert('you clicked ' + e.data.idx);
});
}
//
// let's creat 20 buttons
//
for(var j = 0; j < 20; j++) {
$('body').append($('<button/>', {type: 'button', id: 'question' + j, text: 'Click Me ' + j}))
}
//
// Passing data to the handler
//
for(var i = 0; i < 20; i++) {
$('#question' + i).on('click', {'idx': i}, function(e) {
console.log('you clicked ' + e.data.idx);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can get by with assigning the click handler once (or at least not making many unnecessary closures). Put all the divs in one class mydivs, then:
$(document).ready(function(){
$('.mydivs').click(function(){
// Get the number starting from the ID's 6th character
// This assumes that the common prefix is "mydiv"
var i = Number(this.id.slice(5));
alert('you clicked ' + i);
});
});
This looks at the element's ID to get its number, using the slice string method to strip the initial letters off.
Note: It may be better to use
$('#divcontainer').on('click', '.mydivs', function(){
instead of
$('.mydivs').click(function(){
Generally, if you are looking to assign click handles to a large number of items, you want to have a container (higher level div) that interprets the clicks for you, as the click bubbles up from the dom.
<div id="bucket">
<span class="decorator-class" value="3">
...
</div>
<script>
$(document).ready(function(e){
$("#bucket").live('click', function(){
if(e.target).is('span'){
alert("elementid: " + $(e.target).val());
}
}
}
<script>