alex
alex

Reputation: 53

clearInterval function is not working with backbone.js

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

Answers (2)

alex
alex

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

Elias Van Ootegem
Elias Van Ootegem

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

Related Questions