Reputation: 53
What's wrong with this code?
The setInterval()
does not stop. it´s a infinity looping.
Here is the code of the view.
var chat = require('core/chat');
var Backbone = require('backbone');
var $ = require('jquery');
var agentOfferTemplate = require('hbs!templates/agent-offer');
var contador = 20;
var intervalID;
AgentOfferView = Backbone.View.extend({
template : agentOfferTemplate,
initialize : function() {
this.timeAccept();
},
render : function() {
this.$el.append(this.template(this.model.toJSON()));
return this;
},
timeAccept : function(){
if (contador > 0){
$('#tempo').html(contador);
$('#barra-interna').css('width', contador * 10);
intervalID = setInterval(this.timeAccept, 1000);
contador = contador - 1;
}
else {
window.clearInterval(intervalID);
intervalID = null;
$('#countdown-container').hide();
contador = 20;
}
}
});
return AgentOfferView;
Upvotes: 0
Views: 816
Reputation: 53
I solved.
timeAccept : function(){
var intervalId = setInterval(
function(){
if (contador > 0){
$('#tempo').html(contador);
$('#barra-interna').css('width', contador * 10);
contador--;
}else{
clearInterval(intervalId);
$('#countdown-container').hide();
contador = 20;
}
}, 1000);
}
This way works fine.
Upvotes: 0
Reputation: 76413
When a function is called using either setTimeout
or setInterval
, the this
keyword looses its reference (the function is invoked in a new context). this
will, generally speaking, reference either null
(in strict mode) or the global object.
Read the section entitled The "this" problem on MDN for more details. Basically, you're passing a reference to a function to window.setInterval
, which calls that function in the context of the setInterval
function, which is obviously window
... Since the global object clearly doesn't have a timeAccept
method, your timout loop runs but once, not 20 times. It's as simple as that.
The quickest way around the issue IMO is to use a closure, and pass the entire context to the interval function:
It is, thankfully, an easy fix:
timeAccept : function()
{
if (contador > 0)
{
$('#tempo').html(contador);
$('#barra-interna').css('width', contador * 10);
intervalID = setTimeout((function(context)
{//pass current this reference to closure
return function()
{//instead of this, use context
setInterval(context.timeAccept, 1000);
};
}(this)),1000);
contador--;
}
else
{
clearTimeout(intervalID);
intervalID = null;
$('#countdown-container').hide();
contador = 20;
}
An interval is something that calls a given function over and over again, each X milliseconds. Looking at your code, you'd probably want to use setTimout
, which calls the function only once.
As it now stands, you're creating 20 intervals, each calling the same function every second. Even if contador >= 0
, the intervals keep on calling the function.
Consider the folowing examples:
var intervalId = setInterval(function()
{
console.log('You\'ll see this appear every second');
console.log('This interval has an ID, and it\'s: ' + intervalId);
},1000);
var timeout = setTimeout(function()
{
console.log('This will only appear once, after 1000ms');
console.log('A timeout has an ID, too: ' + timeout);
},1000);
//using the ID's you can cancel both the timeout and the interval using these lines:
clearInterval(intervalId);
clearTimeout(timeout);//usefull if you want to cancel the delayed function call...
Upvotes: 1