jayflo
jayflo

Reputation: 1115

Dojo: maintain reference to widget in event listener callback

I have a Dojo widget that looks as follows:

define([
    // stuff...
], function(declare, lang, win, on, query,
    _WidgetBase, _TemplatedMixin, _OnDijitClickMixin, template){

    return declare("Toolbar", [_WidgetBase, _TemplatedMixin, _OnDijitClickMixin], {
        templateString: template,
        map: null,

        constructor: function(options) {
            // this.map set here
            lang.mixin(this, options);

            if (this.map === null) {
                console.log("Error: no map!");
            }
        },

        postCreate: function() {
            on(this.domNode, ".toolButton:click", this.loadTool);
        },

        // in the following function, this refers to element where event 
        // originated here   
        loadTool: function(e) {
            var clickedTool = "tools/Tool" + this.id[this.id.length - 1];

            require([clickedTool], function(Tool) {
                // Fails: want this.map to refer to map defined by constructor above
                (new Tool({ map: this.map })).placeAt(win.body());
            });
        }
    });
});

At the moment, this Toolbar widget is just an ordered list of buttons, each having class toolButton. When a button is clicked, it will conditionally load the module (which returns another widget) associated to the clicked button. For simplicity, the tool modules are named tools/Tool<some_number> where <some_number> is obtained from the id on the clicked button.

I need to pass the map property of the Toolbar widget into the constructor of the Tool widget as seen on this line:

(new Tool({ map: this.map })).placeAt(win.body());

However, as noted above, within loadTool, this refers to the button that was clicked and not to the Toolbar widget. One possibility would be to called the event listener as

on(this.domNode, ".toolButton:clicked", lang.hitch(this, this.loadTool);

and then obtain the id of the clicked button from the event object...but this seems hacky and like the incorrect way to handle it.

What is the "best practice" for doing this?

Upvotes: 1

Views: 279

Answers (1)

Bobz
Bobz

Reputation: 2604

The best practice is to pass the context to the callback function, like your second approach. This allows you to control how a function executes, particularly in asynchronous operations.

From dojo documentation:

on(something, "click", processEvent);

In asynchronous callbacks such as above, the context that the code is executing in has changed. It will no longer refer to the object that originally provided it, but its context will now refer to the enclosing object, the callback. To get around this, you can use hitch() to force the function to retain its original context.

The same code done properly will look like:

on(something, "click", lang.hitch(this, processEvent));

http://dojotoolkit.org/reference-guide/1.10/dojo/_base/lang.html#dojo-base-lang-hitch

Upvotes: 1

Related Questions