Give arguments to generic eventhandler - javascript

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/

Related

JQuery: using document.on inside if condition [duplicate]

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>

Why does my loop only return the last item of the loop? [duplicate]

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>

self executing anonymous click function in for loop

I need a click function in a for loop, so every id element is clickable. But I also need the i in the click function, that's why I thought a self executing anonymous function would be the best way to do so. But for some reason this is not working, maybe because the click function doesn't allow me to forward a parameter? What have I done wrong?
for (var i = 0; i < countItems; i++) {
$("#item-" + i).click(function(idx) {
alert(idx);
})(i)
}
The self executing function must return a function:
for (var i = 0; i < countItems; i++) {
$("#item-" + i).click(function(indx){
return function(){ //must return a function
alert(indx);
}
}(i));
}
JS Fiddle: http://jsfiddle.net/HuHXr/
As a side note, using bind() javascript method:
for (var i = 0; i < countItems; i++) {
$("#item-" + i).click(function(indx){
alert(indx);
}.bind($("#item-" + i)[0],i));
}
you can try something like this
for (var i = 0; i < countItems; i++) {
$("#item-" + i).click(clickFunctn);
}
function clickFunctn(obj){
var i=$(obj).attr('id').split('-')[1];
alert(i);
}
In this way you will optimize the code and your 'i' will be with you as well, and all items are clickable. And you are just binding one handler function.
for (var i = 0; i < countItems; i++) {
(function(i){
$("#item-" + i).click(function(idx) {
alert(idx);
});
})(i);
}
Also note that idx is the event object.
Fiddle: http://jsfiddle.net/2DRLx/

wrong output from array [duplicate]

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>

Assign click handlers in for loop

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>

Categories