This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Listening for variable changes in JavaScript or jQuery
How can I track if this variable has changed?
var ConditionalFlag = 0;
I tried this:
var ConditionalFlag = 0;
$(ConditionalFlag).change(function () {
alert("Changed");
});
ConditionalFlag++;
But to no avail. I have considered using a 25ms timer to check for change like this:
var ConditionalFlag = 0;
function CheckFlag() {
if (ConditionalFlag > 0) {
alert("Changed");
clearInterval(check);
}
}
var check = window.setInterval("CheckFlag()", 25);
ConditionalFlag++;
However, that seems like overkill. Is there a way to attach an event handler to this variable with jQuery or javascript?
If it's a global variable, you can use property accessors in supported environments...
window._conditional_flag = 0;
Object.defineProperty(window, "ConditionalFlag", {
get: function() { return window._conditional_flag},
set: function(v) { console.log("changed"); window._conditional_flag = v; }
});
There's no "event" that gets triggered when a variable changes. JavaScript doesn't work that way.
When does this variable get changed? Just add a call to a function after it does.
Related
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 4 years ago.
I am trying to create event listeners for a pure JS dropdown menu. When I try to create the listeners using a for loop I get an error and it doesn't work, but when I create them manually using arrays they work perfectly. What am I missing?
var dropDown = document.getElementsByClassName('nav-sub__mobile-dropdown');
var subNavList = document.getElementsByClassName('nav-sub__list');
for ( i = 0; i < dropDown.length; i++) {
dropDown[i].addEventListener('click', function() {
subNavList[i].classList.toggle('nav-sub__list--active');
});
}
The above doesn't work, but if I create the event listeners manually using the arrays it does work.
dropDown[0].addEventListener('click', function() {
subNavList[0].classList.toggle('nav-sub__list--active');
});
dropDown[1].addEventListener('click', function() {
subNavList[1].classList.toggle('nav-sub__list--active');
});
dropDown[2].addEventListener('click', function() {
subNavList[2].classList.toggle('nav-sub__list--active');
});
When I use the for loop I get the following error code in my console.
Uncaught TypeError: Cannot read property 'classList' of undefined
UPDATE SOLVED PROBLEM
I was able to solve the problem using let thanks to Ben McCormick's comment here:
JavaScript closure inside loops – simple practical example
The solution was to simply use let in the for loop.
for (let i = 0; i < dropDown.length; i++) {
Because when the click function is called, the variable i has the last value it held, dropDown.length, not the loop value at the time addEventListener was called.
What you want is something like this:
for ( i = 0; i < dropDown.length; i++) {
function addListener(n) {
dropDown[n].addEventListener('click', function() {
subNavList[n].classList.toggle('nav-sub__list--active');
});
}
addListener(i);
}
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 7 years ago.
I have a method of an object that is called upon click, and the this unfortunately refers to the window object instead of the object that I want it to be referring to.
I've read a several posts that mention this issue, but I have not found/understood any alternatives for my situation.
Any assistance in which direction to go would be appreciated
JSFIDDLE
var IceCream = function(flavor) {
this.tub = 100;
this.flavor = flavor;
};
IceCream.prototype = {
scoop: function() {
this.updateInventory();
alert("scooping");
},
updateInventory: function() {
this.tub--;
alert(this.tub);
}
};
var vanilla = new IceCream("vanilla");
vanilla.scoop();
$('button').click(vanilla.scoop);
$('button').click(function(){
vanilla.scoop();
});
Change the last line to this should make it work. The $.fn.click function takes a callback, with event as the first argument, and binds the element as this, not window.
------------Edit------------
To make this a little bit cleaner, you can define a function to return a click function. Define your class like so:
IceCream.prototype = {
scoop: function() {
this.updateInventory();
alert("scooping");
},
updateInventory: function() {
this.tub--;
alert(this.tub);
},
makeClickFn: function(){
var self = this;
return function(event){
self.scoop();
};
}
};
And when you need to bind the click function:
$('button').click(vanilla.makeClickFn());
jsfiddle: https://jsfiddle.net/L7e71sLL/
$('button').click(vanilla.scoop.bind(vanilla));
Bind, creates a function whose this variable is bound to the given object. In this case vanilla
Inside $('button').click() the scope will be of the button. So you need to bind the vanilla scope to the onClick function
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I have following code :
function A() {
this.value = 'a_value';
}
A.prototype.getValue = function(){
console.log(this.value); // got undefined, expected 'a_value'
}
setTimeout(new A().getValue, 100);
why i get this.value as undefined.?
and how how do i access this.value?
EDIT : i am not allowed to change the setTimeout line (last line) of code.
Hint: have you tried console.log(this);?
You are only passing the getValue function to setTimeout, not its context. Something like this would work: setTimeout(function() {new A().getValue();},100); But without changing that last line, there's basically nothing you can do.
you can avoid using the this altogether and not having this kind of problems with the following technique :
var A = function () { // no new no this
var value = 'a_value';
var getValue = function(){
console.log(value);
};
return Object.freeze({
getValue ,
});
};
setTimeout(A().getValue, 100);
or write
var a = new A();
before, and then
setTimeout(a.getValue.bind(a), 100);
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
JavaScript setInterval and `this` solution
(9 answers)
Closed 8 years ago.
EDIT: The practice below is NOT correct. The solution is to store "this" in another variable and use that in the setInterval function. See answers below.
this.growImage = function() {
console.log("growImage:" + this.dom.id + "counter:" + this.grow_counter);
if(this.grow_counter == 0) {
this.tim_grow = window.setInterval(
/******* FUNCTION TO BE CALLED BY SETINTERVAL ********/
function() {
this.grow_counter++;
console.log("this.growStepByStep(): this.grow_counter = " + this.grow_counter); /*this is displayed as NaN */
if(this.grow_counter > this.times) {
window.clearInterval(this.tim_grow);
this.grow_counter = 0;
}
}
/******* FUNCTION TO BE CALLED BY SETINTERVAL ********/
,
20);
}
}
EDIT: The above solution is NOT correct.
It does not work. The console log does not "see" this.grow_counter, and displays a NaN instead. this.grow_counter is just a numeric value.
NOTE: that this function uses this inside it, so other simpler solutions won't do either.
Thanks in advance!
The value of this is NOT preserved in your setInterval() callback. You have to save that value you want to another variable before the setInterval() call and use that inside the setInterval().
this.growImage = function() {
console.log("growImage:" + this.dom.id + "counter:" + this.grow_counter);
if(this.grow_counter == 0) {
var self = this;
this.tim_grow = window.setInterval(
/******* FUNCTION TO BE CALLED BY SETINTERVAL ********/
function() {
self.grow_counter++;
console.log("self.growStepByStep(): self.grow_counter = " + this.grow_counter); /*this is displayed as NaN */
if(self.grow_counter > this.times) {
window.clearInterval(self.tim_grow);
self.grow_counter = 0;
}
}
/******* FUNCTION TO BE CALLED BY SETINTERVAL ********/
,
20);
}
}
Or, if you are using modern browsers only, you can also use .bind() to manipulate the value of this to be set as you want like this:
this.growImage = function() {
function intervalCallback() {
this.grow_counter++;
console.log("this.growStepByStep(): this.grow_counter = " + this.grow_counter); /*this is displayed as NaN */
if(this.grow_counter > this.times) {
window.clearInterval(this.tim_grow);
this.grow_counter = 0;
}
}
console.log("growImage:" + this.dom.id + "counter:" + this.grow_counter);
if(this.grow_counter == 0) {
this.tim_grow = window.setInterval(intervalCallback.bind(this), 20);
}
}
Neit is correct, but to give a little bit more info.
You aren't understanding the scope that you are in when inside the setInterval.
Inside of your setInterval, you've created a new scope and 'this' only refers to things inside that new scope. His/her suggestion of setting a variable me = this and then using me.grow_counter means you are storing the outer scope in the variable 'me', which can then be used in your setInterval scope (although I would like to see a better variable name!).
Hope that helps.
i have the following code :
$(document).ready(function () {
for (i = 1; i <= number_of_banners; i++) {
var selector = "#link_" + i;
$(selector).click(function () {
alert(i);
});
}
});
but the alert() can't get the "i" variable from the for loop.
How can I use the i variable of for loop inside the .click function ?
you can use this code :
$(document).ready(function () {
for (var i = 1; i <= number_of_banners; i++) {
var selector = "#link_" + i;
$(selector).on('click', {id: i}, function (e) {
alert(e.data.id);
});
}
});
you should use on method and use click argument in it instead of using onclick method
Using jQuery .on(event, data, handler) you can do it easily.
$(document).ready(function () {
for (var i = 1; i <= number_of_banners; i++) {
var selector = "#link_" + i;
$(selector).on('click', {id: i}, function (e) {
alert(e.data.id);
});
}
});
Working sample
Might this happen be due the fact of the JavaScript hoisting JavaScript Scoping mechanism??
For instance:
example of wrong loop variable binding
doesn't work as JavaScript uses function scope rather than block scope as we're usually accustomed from other languages like Java and C#. In order to make it work, one has to create a new scope by explicitly creating a new anonymous function which then binds the according variable:
example of correct loop variable binding
I know this doesn't directly answer the question above, but might still be useful though for others stumbling over this question.
I think you can pass it as a parameter into the anonymous function as long as the function is declared within a scope that can access i.
function (i) {
alert(i);
}
a quick solution would be to use the eventData and store the current i in that:
$(document).ready(function () {
for (var i = 1; i <= number_of_banners; i++) {
var selector = "#link_" + i;
$(selector).bind('click', i, function (e) {
alert(e.data);
});
}
});
if you are using jquery 1.7+ then use on instead of bind