Randomblue
Randomblue

Reputation: 116423

JavaScript: problem with object

I am programming a little timer. The code is as follows:

var counter = {
    seconds: 100,
    clock: function () {
        $('input').val(this.seconds);
        this.seconds -= 1;
        setTimeout(this.clock(), 1000);
    }
};

counter.clock();

with a working example on http://jsfiddle.net/4ktEG/

Somehow each time I run the code I get a different answer. What is the problem?

Upvotes: 1

Views: 96

Answers (6)

user113716
user113716

Reputation: 322612

jQuery has the jQuery.proxy()[docs] method for binding the this value.

setTimeout($.proxy(counter,'clock'), 1000);

The $.proxy will return a function that invokes counter.clock with counter bound as the this value.


Or you can use it like this to permanently bind counter to counter.clock:

var counter = {
    seconds: 100
};

counter.clock = $.proxy( function () {
    $('input').val(this.seconds);
    this.seconds -= 1;
    setTimeout(this.clock, 1000);
}, counter);

counter.clock();

Example: http://jsfiddle.net/bmYAN/

Upvotes: 1

cellcortex
cellcortex

Reputation: 3176

The timeout will execute in a global context. Hence the 'this' inside the handler will refer to the global context. You have to bind the function to the wanted context to achieve the desired result. Look into function.call or function.apply which take a context parameter.

var counter = {
    seconds: 100,
    clock: function () {
        $('input').val(this.seconds);
        this.seconds -= 1;
        var closure = function() {
            counter.clock.call(counter);
        };

        setTimeout(closure, 1000);
    }
};

counter.clock();

Upvotes: 0

Darm
Darm

Reputation: 5659

Use:

var counter = {
    seconds: 100,
    clock: function () {
        $('input').val(counter.seconds);
        counter.seconds -= 1;
        setTimeout(counter.clock, 1000);
    }
};

counter.clock();

You used "this" inside a function, what you want is to refer to the "counter" object.

Upvotes: 0

ShankarSangoli
ShankarSangoli

Reputation: 69915

When you say

setTimeout(this.clock(), 1000); //the clock method will be called right away.

Use this instead

setTimeout(this.clock, 1000); 

Upvotes: 0

Jacob
Jacob

Reputation: 3965

If you want the input to show "100", then disappear when the setTimeout is called, then you have to take out the brackets on "this.clock()"

Therefor:

var counter = {
seconds: 100,
clock: function () {
    $('input').val(this.seconds);
    this.seconds -= 1;
    setTimeout(this.clock, 1000);
}
};

counter.clock();

Upvotes: 0

Jared Farrish
Jared Farrish

Reputation: 49238

This does the countdown you're looking for.

var counter = {
    seconds: 100,
    clock: function () {
        $('input').val(this.seconds);
        this.seconds -= 1;
        setTimeout(function(){counter.clock()}, 1000);
    }
};

counter.clock();

http://jsfiddle.net/4ktEG/13/

Upvotes: 7

Related Questions