0

I've a page that is generated dynamically, and that includes certain number (user-dynamically-defined) of advanced scatter plot charts. I intend to create a JavaScript object which defines the scatter plot itself, i.e. which takes some parameters, some data, and some container ID, and which will create the various elements needed to obtain the visualisation: canvas elements, toolbar, etc.. To do so, I started with the following (simplified) class:

(function () {
    if (!this.namespace) { this.namespace = {};}

    this._instances = { index: 0 };

    this.namespace.ScatterPlot = function (containerId, file, options) {
        _instances.index ++;
        this.id          = this.containerId+"-"+_instances.index ;
        this.containerId = containerId ;
        _instances [this.id] = this;

        // ... Do stuffs with file and options ...

        // Initialize elements once the DOM is ready
        $(this.updateDOM);
    }

    namespace.ScatterPlot.prototype = {
        updateDOM: function() {
            $("<canvas>")
                .click(clickCallback)
                .appendTo("#"+this.containerId);
            //(...)
        },

        clickCallback: function() {
            alert("Some click: "+this.id);
        }
    }


})();

Each object can be created with:

var v1 = new namespace.ScatterPlot("container1", "foo", "foo");
var v2 = new namespace.ScatterPlot("container2", "foo", "foo");

There are two problems here: (1) in updateDOM, 'this' does not make reference to my initial ScatterPlot object, which means that this example will never work, and (2) similarly, the clickCallback will not be able reference the scatterplot with 'this' either.

I'm new to javascript, and I'm still struggeling to understand the logic of OO programming in javascript, so the question is: I'm I taking the wrong direction here ? After some digging, I could roughly achieve what I wanted by passing this to updateDOM:

$(this.updateDOM(this)); // This blows my eyes but does the trick, at least partially

updateDOM: function(that) {
    $("<canvas>")
        .click(that.clickCallback)
        .appendTo("#"+that.containerId);
    //(...)
},

clickCallback: function() {
    // Not working either... Should pass 'that' to the function too
    alert("Some click: "+this.id);
}

But I don't feel this patters to be very elegant... And the problem is not fixed either regarding the click callback.

Thoughts ?

1
  • 1
    Your trick does not do what you expect, as it invokes the function immediately and adds undefined as a DOMready listener Commented Nov 20, 2012 at 14:01

1 Answer 1

2

Have a look at MDN's introduction to the this keyword.

The standard ways of dealing with that issue are using a that variable - not as an argument, but in a separate function:

var that = this;
$(function() {
    that.updateDOM();
});

// or

$(this.getClickCallback());
...
namespace.ScatterPlot.prototype.getClickCallback =  function() {
    var that = this;
    return function clickCallback(e) {
        alert("Some click: "+that.id);
    };
};

Alternatively, you can always use .bind() (or $.proxy for older browsers) which do quite what the second example does in a more generic way:

$(this.clickCallback.bind(this));
Sign up to request clarification or add additional context in comments.

3 Comments

The bind method seems to be a working and consise enough solution... Is it the best practice ? Problem seems to be solved (jsfiddle.net/7t9Ju/1), and any further comments will be welcome though, as I hope to take the best direction in terms of javascript good practices
bind is supported only by ES5.1 engines, so older IEs etc pass out. You can easily shim it for them, use libraries (_.bind, jQuery.proxy) or just don't care about them. The that variable is best practise, especially if you can use it more than once.
Yes it seems so. Here is a very good article dealing with bindings: alistapart.com/articles/getoutbindingsituations. Thanks for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.