setInterval after setTimeout is executed constantly - javascript

I'v got code that checks current position of right top corner of some element:
function checkContentPos(e) {
var positionLeft = 0,
checkTabPos = null,
pos;
e = $(e).filter('li');
alert($(e).attr('class'));
//alert($(e).attr('class'));
checkTabPos = setInterval(
function () {
ii++;
debug(ii);
pos = $(e).offset();
pos['left'] += parseInt($(e).css('width'));
positionLeft = pos.left;
debug(positionLeft);
}, 40);
function stopCheckTabPos() {
debug('stopCheckTabPos invoked')
clearInterval('checkTabPos');
}
setTimeout(stopCheckTabPos, 400);
return(positionLeft);
};
But I looks like its looped to instanity. After setTimeout it's still constantly invoked.

clearInterval('checkTabPos');
Don't use quotes here. How would that even work? You need to pass in the identifier returned by setInterval, not some arbitrary string.

You're invoking clearInterval with the string 'checkTabPos' when you should be using it with the variable
function stopCheckTabPos() {
debug('stopCheckTabPos invoked')
clearInterval(checkTabPos);
}

Related

How can I increment the value of a parameter in an object using a function?

I want to be able to increment/change the value of a parameter inside an object. I want the value to change by accessing the value of a variable that is incrementing inside another function.
The example code below shows what I am trying to do. I would like options.number to increase as i inside masterLoop increases.
I know that i isn't defined in the scope of function calc(), but I can't think of a way to retrieve the value of i while maintaining this general code structure.
(function masterLoop(i) {
setTimeout(function() {
++i;
masterLoopStage = i;
console.log('Stage is: ' + i);
masterLoop(i);
}, 5000)
})(1);
function calc() {
number = i; // I know i isn't defined in this scope, but I can't figure out how access the incrementing value of i inside this function
return number;
}
var options = {
number: calc() // I want this vale to increase along with i inside masterLoop()
};
setInterval(function() {
console.log(options.number);
}, 5000);
Typically, in cases like this, I would try to use a return to retrieve a value, but I wasn't able to find a solution with that either since the incrementing value is inside a setInterval and thus its scope isn't available to the return.
Here is an example of that:
function calc() {
var foo = 1;
setInterval(function() {
var foo = foo + 1;
}, 1000);
return foo; // the incrementing value of foo is not available outside the scope of setIterval, so this won't work. The return also won't work inside setInterval.
}
var optionsConstant = {
maxVolume: 10
};
var options = {
maxVolume: optionsConstant.maxVolume + calc() // I want calc() to be able to increment along with foo in the setInterval above.
};
setInterval(function() {
var maxVolume = options.maxVolume;
console.log('maxVolume: ' + maxVolume);
}, 5000);
Taking your second attempt, you could make calc an immediately invoked function expression -- providing a closure -- and in it return a function that has access to foo.
Then, to keep the final syntax of options.maxVolume, you should define that property as a getter, so that in fact it will execute some code when accessed, calling calc():
var calc = (function () { // create closure for foo
var foo = 1;
setInterval(function() {
foo = foo + 1; // remove var!
}, 100);
return function calc() { // return a function
return foo;
}
})();
var optionsConstant = {
maxVolume: 10
};
var options = {
get maxVolume() { // make it a getter
return optionsConstant.maxVolume + calc();
}
};
setInterval(function() {
var maxVolume = options.maxVolume;
console.log('maxVolume: ' + maxVolume);
}, 500);
Can you declare the increment variable outside the masterloop function scope so the other functions can access it and read its' value when needed?
You'll need to make sure to re-initialize it's value when appropriate.
I think you need to use a closure. Here's one example:
let returnI = (function masterLoop(i) {
setTimeout(function() {
++i;
masterLoopStage = i;
console.log('Stage is: ' + i);
return masterLoop(i);
}, 5000)
})(1);
function calc() {
number = returnI;
return number;
}
var options = {
number: calc()
};
setInterval(function() {
console.log(options.number);
}, 5000);

Why object property became undefined when using setInterval

As below code, I make an object named "test", and give it properties and method.
The property came from its argument.
And I try to call the method every 2 sec after onload, and the result shows undefined.
But if I only call the method not using setInterval(), like this
window.onload = function() {
giveword.showWord();
}
I'll be able to show the text "Hi".. Why is that?
var giveword = new test("Hi");
function test(word) {
this.word = word;
}
test.prototype.showWord = function() {
document.getElementById("msg_box").innerHTML = this.word;
}
window.onload = function() {
setInterval(giveword.showWord, 2000);
}
Thanks for help...
The reason is because in your test.prototype.showWord function your this object is referring to the context in which the function is called, which is the window object when called from setInterval.
I think what you want to do is use a closure to make the context of showWord() be the giveword instance like this:
var giveword = new test("Hi");
function test(word) {
this.word = word;
}
test.prototype.showWord = function() {
document.getElementById("msg_box").innerHTML = this.word;
}
window.onload = function(){
setInterval(function(){giveword.showWord();}, 2000); // <<-- here's the closure
}
The difference is that with the closure you're telling the setInterval function to call a function within the context as it was when the setInterval was declared. When setInterval was declared there was a variable in scope called giveword that had a method showWord() that returns the value of your initial input. (Closures are hard to explain, and I'm afraid you'd be best served by someone else explaining them if you need more info.)
This solution this now so easy, use an arrow function in setInterval. Here is an example using setInterval inside of an object method.
const mobile = {
make: 'iPhone',
model: 'X',
battery: 10,
charging: false,
charge: function() {
if(this.battery < 100) {
this.charging = true;
console.info('Battery is charging...');
let interval = setInterval(() => {
this.battery = this.battery + 10;
console.info(mobile.battery);
if( this.battery === 100){
this.charging = false;
clearInterval(interval);
console.info('Battery has finished charging.');
}
}, 100);
}
else {
console.info('Battery does not need charging.');
}
}
}

Loop a function while key is pressed

I'm trying to move a div up and down using two keys in Javascript. The idea is that while a certain key is depressed, a function loops and adds to the div's 'top' style value each time. The basic function works, but I can't get it to loop and I can't get anything to respond to a keypress.
It's hard to find info on keypress handling in Javascript, it seems most people use jQuery to handle that.
Is my use of the do-while loop correct? is there a better way to handle keydown and keyup events?
Here's my code:
var x = 0;
console.log(x);
function player1MoveDown() {
var value = document.getElementById("player1").style.top;
value = value.replace("%", "");
value = parseInt(value);
value = value + 1;
value = value + "%";
document.getElementById("player1").style.top = value;
console.log(value);
} //moves paddle down; adds to paddle's 'top' style value
function player1MoveSetting() {
x = 1;
do {
setInterval(player1MoveDown(), 3000);
}
while (x == 1);
console.log(x);
} //paddle moves while x=1; runs player1MoveDown function every 3 seconds
function player1Stop() {
x = 0;
}
And here's the relevant bit of HTML:
<div class="paddle" id="player1" style="top:1%" onkeydown="player1MoveSetting()" onkeyup="player1Stop()"></div>
You cannot attach a keydown event to a div, unless it has a tabindex:
<div class="paddle" id="player1"
onkeydown="player1MoveSetting()"
onkeyup="player1Stop()"
tabindex="1"
>
</div>
You can replace all this code:
var value = document.getElementById("player1").style.top;
value = value.replace("%", "");
value = parseInt(value);
value = value + 1;
value = value + "%";
document.getElementById("player1").style.top = value;
… with this:
var p1= document.getElementById('player1');
p1.style.top= parseInt(p1.style.top)+1+'%';
This calls the return result of player1MoveDown:
setInterval(player1MoveDown(), 3000);
Since player1MoveDown doesn't return anything, it's the equivalent of
setInterval(null, 3000);
To call the function every 3 seconds, do this instead:
setInterval(player1MoveDown, 3000);
This creates an infinite loop:
x = 1;
do {
setInterval(player1MoveDown, 3000);
}
while (x == 1);
Even though keyup will set the global x to 0, it will never run because the loop never ends.
Instead, create a timer variable, which is set on keydown and cleared on keyup.
Complete JavaScript Code
var timer;
function player1MoveDown() {
var p1= document.getElementById('player1');
p1.style.top= parseInt(p1.style.top)+1+'%';
console.log(p1.style.top);
}
function player1MoveSetting() {
if(timer) return;
timer= setInterval(player1MoveDown, 100);
}
function player1Stop() {
clearInterval(timer);
timer= null;
}
document.getElementById('player1').focus();
Working Fiddle

Call function in custom function

I'm trying to figure out how this custom jQuery functions work by experimenting a bit. I can't however get it to work properly. I'm trying to call the prepareSlide function in my setInterval but it says prepareSlide is not defined
$('document').ready(function(){
jQuery('.item_holder').itemSlider({
start: 1,
carousel: true
});
});
$.fn.itemSlider = function (details) {
var currentSlideNumber = (details && details.start > 0) ? details.start : 1;
this.prepareSlide = function(slideNumber) {
alert(1)
}
//Set an interval
var itemToSlide = currentSlideNumber + 1;
slideTimer = setInterval("prepareSlide(" + itemToSlide + ")", 5000);
}
You should provide a function to the first argument of setInterval. Also, to provide the context properly to the function invocation, a quick method is to preserve this by having another variable reference it, which in this case, we call self
var self = this;
slideTimer = setInterval(function(){
self.prepareSlide(itemToSlide)
}, 5000);

jscript/jquery: fade in divs 1 by 1, with pause inbetween

I am totally stumped here.
I have a bunch of messages, each within a div "msg_feed_frame_$i" which increases, so message 1 is in div "msg_feed_frame_1", msg 2 is in "msg_feed_frame_2", etc etc. I want to fade these messages in one by one using jquery, but for some reason no matter what I do with settimeout and setinterval, the code immediately fades them all in simultaneously.
This is what i've got so far:
function feed(i)
{
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000);
}
function timefade()
{
var num = 1;
for (num=1; num<=10; num++)
{
var t=setTimeout(feed(num),1000);
}
}
$(document).ready(function(){
timefade();
});
Your problem is that the for loop executes quickly and sets a timeout 1000ms from now for each function call. Here's one way you could remedy this:
function feed(i) {
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000);
}
function timefade() {
var num = 1;
var fadeIt = function(i) {
return function() { feed(i); };
};
for (num = 1; num <= 4; num++) {
var t = setTimeout(fadeIt(num), num * 1000);
}
}
$(document).ready(function() {
timefade();
});
Additionally, your original code was passing setTimeout the results of the feed(i) function call (undefined), and it expects an object of type function. I added a helper function that returns a reference to a function that will call feed with the correct argument.
Capturing the value of num inside a function is called a closure, and it can be confusing at first. Check this post out for some good explanations of closures inside loops and while they're necessary.
Here's your example, working: http://jsfiddle.net/andrewwhitaker/tpGXt/
Try using jQuery's .delay() function...
function feed(i){
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000).delay(1000);
}
function timefade(){
var num = 1;
for (num=1; num<=10; num++){
feed(num);
}
}
$(document).ready(function(){
timefade();
});

Categories

Resources