0

I have some conceptual problem with using Dojo's class-like objects created with dojo/_base/declare.

I have created the following module:

define(["dojo/_base/declare", ....], function(declare,....){
    return declare('my.widget', null ,function(..){
     startup: function() {
       ....
       new Button({onClick: this.newItem}, newButtonNode)
     },
     newItem: function() {
       this.openDialog({}, this.saveItemCallback)
     },
     openDialog: function(item,callback){...},
     saveItemCallback: function(item){....}
    })
})

The problem is, that the function newItem isn't functioning, because when it's called from button click, this points to Button widget, and not to the 'my.widget' instance.

I'm confused. How can I refer to the 'my.widget' instance? In the Dojo classes I've read the current instance is available under this.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223
  • For the `openDialog` function, bear in mind that sometimes it's cleaner to [return a `Promise`](http://dojotoolkit.org/documentation/tutorials/1.9/promises/) rather than requiring callbacks as parameters. – Darien Oct 16 '13 at 17:20

2 Answers2

1

If you then want to call newItem with the correct scope, you could use the dojo/_base/lang, hitch() function.

define(["dojo/_base/declare", "dojo/_base/lang", ....], function(declare, lang, ....){
    return declare('my.widget', null ,function(..){
     startup: function() {
       new Button({onClick: lang.hitch(this, "newItem"}, newButtonNode)
     },
     newItem: function() {
       this.openDialog({}, this.saveItemCallback)
     },
     openDialog: function(item,callback){...},
     saveItemCallback: function(item){....}
    })
});

The hitch() function will make sure that the this reference is correct. This sounds like real magic, but it uses some kind of reflection behind the screens to execute the function.

What it really does is using the Function.prototype.apply function to get the magic started. As you can read in this article it accepts a context and the parameters. So it will in fact change the this reference when newItem is executed.

g00glen00b
  • 41,995
  • 13
  • 95
  • 133
  • OK, but it's not the problem. The problem is, that for the newItem function, 'this' is the Button, not 'myInstance'. 'myInstance' is visible only within 'startup' function. – Danubian Sailor Oct 16 '13 at 07:55
  • @ŁukaszL. fixed it. It's pretty much the same as Chris Hayes posted, but with the new AMD syntax. – g00glen00b Oct 16 '13 at 07:59
  • Yest, this is it! I have still problems understanding, what 'hitch' is doing. – Danubian Sailor Oct 16 '13 at 08:06
  • I editted my answer to explain what `hitch` does. Behind the screens it's using some kind of reflection to do the magic stuff. There is a function called `apply` which allows you to modify what `this` is referring to. – g00glen00b Oct 16 '13 at 08:12
  • Yet, knowing what to search, I've found multiple usages of lang.hitch in Dojo code, so your answer is the canonical way of doing things in Dojo. – Danubian Sailor Oct 16 '13 at 08:25
0

You can use dojo.hitch to attach a context to a function:

define(["dojo/_base/declare", ....], function(declare,....){
    var myFunc = dojo.hitch(this, function() { 
       this.openDialog({}, this.saveItemCallback)
    });

    return declare('my.widget', null ,function(..){
     startup: function() {
       ....
       new Button({onClick: this.newItem}, newButtonNode)
     },
     newItem: myFunc,
     openDialog: function(item,callback){...},
     saveItemCallback: function(item){....}
    })
})

By doing so, you are effectively stating that within the anonymous function passed to dojo.hitch, this refers to the first argument passed (which could be any object).

Chris Hayes
  • 11,471
  • 4
  • 32
  • 47