前回の記事の続き。
dojoでカスタムウィジェットを作成するチュートリアルを読んでいたけど
マウスオーバー時のアクションの部分でundefinedエラーが発生していた。
該当のコードはこんな感じ。
// colors for our background animation baseBackgroundColor: '#fff', mouseBackgroundColor: '#def', postCreate: function(){ // Get a DOM node reference for the root of our widget var domNode = this.domNode; // Run any parent postCreate processes - can be done at any point this.inherited(arguments); // Set our DOM node's background color to white - // smoothes out the mouseenter/leave event animations domStyle.set(domNode, "backgroundColor", this.baseBackgroundColor); // Set up our mouseenter/leave events - using dojo/on // means that our callback will execute with `this` set to our widget on(domNode, 'mouseenter', function (e) { this._changeBackground(this.mouseBackgroundColor); }); on(domNode, 'mouseleave', function (e) { this._changeBackground(this.baseBackgroundColor); }); }, _changeBackground(toCol) { ...
チュートリアル通りに実装したのですが、
this._changeBackgroundやthis.mouseBackgroundColorがundefinedだと怒られる...
で、調べてわかったことですが
これチュートリアルの記述が間違ってますね。
正しくはこうです。
(onメソッド内部のみ)
on(domNode, 'mouseenter', lang.hitch(this, '_changeBackground', this.mouseBackgroundColor));
つまり、lang.hitchを使う必要があります。
なんで?という部分については
lang.hitch()のリファレンスにサンプルコード含めてわかりやすく書いてた。
dojo/_base/lang — The Dojo Toolkit - Reference Guide
require(["dojo/on"], function(on){ var processEvent = function(e){ this.something = "else"; }; on(something, "click", processEvent); });
こういう書き方をしてもうまくいかないのは
非同期のコールバック関数(onで呼び出してる関数)のcontextが変わっているからなんだと。
contextという単語にしっくりくる日本語訳はわからんが
「thisが示すもの」が変わっている、と考えるとよさそう。
つまり、関数を定義している時のthisと、実際に非同期でコールバックが呼ばれている時のthisは別物ってことですね。
それを回避するために、lang.hitchを使います。
上の例だと次のように書けばよい。
require(["dojo/on", "dojo/_base/lang"], function(on, lang){ var processEvent = function(e){ this.something = "else"; }; on(something, "click", lang.hitch(this, processEvent)); });