This question already has answers here:
Javascript infamous Loop issue? [duplicate]
(5 answers)
Closed 8 years ago.
I have function with loop and jQuery click function which I would like, after click, execute specific function. The a.id class is important, so like jQuery click definition. After click on element with specific id, I would like execute specific function. What can change is only function b?
var a = {
id: { "id1": function () { console.log(1) }, "id2": function () { console.log(2) }, "id3": function () { console.log(3) } },
b: function () {
$this = this;
for (v in $this.id) {
$("#" + v).click(function () {
$this.id[v]();
});
}
}
}
After i click on element, i want see id1 = 1, id2 = 2, id3 = 3. But this code write value 3 for each element. This example is very simple. Problem is variable reference i know, but i can't find correct solution. Thanks
Wrap it in an IFFE function. Read more about scope and IIFE's here http://benalman.com/news/2010/11/immediately-invoked-function-expression/.
I have provided a fiddle with an example related to your question:
http://jsfiddle.net/rtmeo4nx/3/
function() {
var $this = this;
for (var v = 0; v <= 4; v++) {
(function() {
var i = v;
$("#v" + i).on("click", function(e) {
e.stopPropagation();
alert('hi' + i);
});
})();
}
}
Related
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 4 years ago.
I am new in JavaScript and jQuery. I have found a problem which I can't solve myself.
for (i = 0; i < 12; i++)
{
$("#c" + i).on("click", function () { alert(i) });
}
It attaches events to every element with id from c0 to c11 with alert(12) instead of alert(i)...
On the other hand
$("#c0").on("click", function () { alert(0) });
$("#c1").on("click", function () { alert(1) });
$("#c2").on("click", function () { alert(2) });
...
Works good. Isn't it the same?
This is because of the way var keyword works and also because
$("#c" + i).on("click", function () { alert(i) });`
is async in nature.
just do this instead,
Quick Fix
for (let i = 0; i < 12; i++)
{
$("#c" + i).on("click", function () { alert(i) });
}
Explanation: Your code does not work because $('#c').on('click', fun) is async in nature what that means is this function function () { alert(i) } will be executed later in time, by the time that happens your for loop will be finished with the value of i = 12 hence, you are getting 12 as a value for all handlers.
Now the question is how adding let fixed this?
The answer is simple, Let follows Block scoping whereas var or no var ( global ) is not blocked scoped. var has a functional scope and to achive the same with var you'll need to do something like this.
for(var i = 0; i < 12; i++) {
(function(i) {
$("#c" + i).on("click", function () { alert(i) });
})(i);
}
This question already has answers here:
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 6 years ago.
I saw this on some sample code
var foo = (function(){
//some code
})();
What does this mean? and how is it different from
var foo = function() {
//some code
}
I saw that here where the original code was:
var registrationForm = (function() {
var callbacks = [];
function inputChanged() {
// Execute registered callbacks
for(var i = 0; i < callbacks.length; i++) {
callbacks[i](isValid());
}
}
function isValid() {
// Check whether form is valid or not
return !!(name.value) && !!(dateOfBirth.value) && !!(email.value);
}
function getFormData() {
// Get form values
return {
name: name.value,
dateOfBirth: dateOfBirth.value,
email: email.value
};
}
var name = document.getElementById("inpName");
var dateOfBirth = document.getElementById("inpDob");
var email = document.getElementById("inpEmail");
name.addEventListener("change", inputChanged);
dateOfBirth.addEventListener("change", inputChanged);
email.addEventListener("change", inputChanged);
return {
isFormValid: function() {
return isValid();
},
getFormData: function() {
return getFormData();
},
attachFormChanged: function(cb) {
callbacks.push(cb);
}
};
})();
That is called an immediately invoked function expression. It's invoked as soon as it's declared, versus the latter, you have to call it to execute it.
This question already has answers here:
Function in JavaScript that can be called only once
(32 answers)
Closed 6 years ago.
Execute function only one time in Javascript, no matter how many times it has been called.
I write the following code, but does not working.
var counter = 0;
if(n.data === YT.PlayerState.BUFFERING) {
setTimeout(function() {
if(counter===0) {
r.frontPlayer.seekTo(10);
counter++;
}}, 2000);
}
Try not to use timeouts, they invite misery and suffering. This is a simple example, I use jquery for attaching the events but the function is independent of jquery. The key thing is using the object, the anonymous function in this case, to track state.
<button id="testButton">
test
</button>
$("#testButton").click(function() {
if (null == this.ran) {
console.log("do something");
this.ran = true;
}
})
Take a look at underscore or lodash's _.once function:
var fn = _.once(function() {
console.log('this will only run once');
});
Or writing it yourself:
var fn = (function() {
var called = false;
var ret;
return function() {
if (called) return ret;
called = true;
// do stuff
// ..
ret = 'some return value';
return ret;
};
})();
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
Below is my javascript code:
function showBranch_init() {
var id_arr = ["jdc_b1","jdc_b2","jdc_b3","jdc_b4"];
for(a=0;a<id_arr.length;a++){
timeoutID = window.setTimeout(function() {
showBranch(id_arr[a]); // <-- Right here
}, 500);
}
}
How can I pass the value of id_arr[a] to showBranch funcion?
Currently the above code returns null for id_arr[a]
by introducing a new scope (by a function call) for each iteration step you can pass the argument like this:
function showBranch_init() {
var id_arr = ["jdc_b1","jdc_b2","jdc_b3","jdc_b4"];
for(a=0;a<id_arr.length;a++){
(function(i) {
timeoutID = window.setTimeout(function() {
showBranch(id_arr[i]); // <-- Right here
}, 500*i);
})(a);
}
}
Updated to fullfill the 2nd req: showBranch() in 500ms steps..
http://jsfiddle.net/HXc4d/
function showBranch_init() {
var id_arr = ["jdc_b1","jdc_b2","jdc_b3","jdc_b4"];
for(a=0;a<id_arr.length;a++){
timeoutID = window.setTimeout(function(idvalue) {
showBranch(idvalue);
}(id_arr[a]), 500);
}
}
EDIT: The problem with your solution is the fact that when the code executes (timeout) id_arr no longer exists in the executing scope, thus leading to undefined result. When sending the variable as an argument it "stays" with the funciton itself, regardless of the executing scope.
function showBranch_init() {
var id_arr = ["jdc_b1","jdc_b2","jdc_b3","jdc_b4"];
timeoutID = window.setTimeout(function() {
for(a=0;a<id_arr.length;a++){
showBranch(id_arr[a]); // <-- Right here
}
}, 500);
}
can you do that?? O_O
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
I have an object containing a number of buttons (label and callback) which I dynamically want to add to the DOM:
var buttons = {
'Save': function() {
return false;
},
'Abort': function() {}
};
for(label in buttons) {
$('#buttonbar').append('<button>' + label + '</button>');
var callback = buttons[label];
$('#buttonbar button:last-child').click(function() {
//var result = callback();
alert(callback);
});
}
But regardless which button I click, the variable callback always contains the function of the last button. See this fiddle.
Any ideas how to solve that?
Thanks to the hint given by Barmar I found the solution:
var buttons = {
'Save': function() {
return false;
},
'Abort': function() {}
};
for(label in buttons) {
$('#buttonbar').append('<button>' + label + '</button>');
var callback = buttons[label];
(function(cb) {
$('#buttonbar button:last-child').click(function() {
alert(cb);
});
})(callback);
}