dojo.declare(
"my.widget.AccountCreator",
[dijit._Widget, dijit._Templated],
{
templatePath: dojo.moduleUrl("my.widget", "templates/AccountCreator.html"),
widgetsInTemplate: true,
_subscriptions: [],
_connects: [],
postCreate: function() {
this._connects.push(dojo.connect(dijit.byId("accountCreatorDialog"), "hide", this, "_handleHideDialog"));
this._subscriptions.push(dojo.subscribe("/acct/created", this, "_handleAccountCreated"));
},
destroy: function() {
// first clean up my connects and handles
dojo.forEach(this._subscriptions, dojo.unsubscribe);
dojo.forEach(this._connects, dojo.disconnect);
this._subscriptions = [];
this._connects = [];
// now go ahead and delete the rest of the widget
this.inherited(arguments);
}
Seems relatively simple, right? Being a good memory citizen and cleaning up just before the widget gets destroyed seems like a win-win situation. However, notice that my collection of dojo.connect handles is named _connects. Check out the source code for dijit._Widget (my.widget.AccountCreator inherits from dijit._Widget):
create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
// summary:
// Kick off the life-cycle of a widget
// params:
// Hash of initialization parameters for widget, including
// scalar values (like title, duration etc.) and functions,
// typically callbacks like onClick.
// srcNodeRef:
// If a srcNodeRef (DOM node) is specified:
// - use srcNodeRef.innerHTML as my contents
// - if this is a behavioral widget then apply behavior
// to that srcNodeRef
// - otherwise, replace srcNodeRef with my generated DOM
// tree
// description:
// Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate,
// etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget
// for a discussion of the widget creation lifecycle.
//
// Of course, adventurous developers could override create entirely, but this should
// only be done as a last resort.
// tags:
// private
// store pointer to original DOM tree
this.srcNodeRef = dojo.byId(srcNodeRef);
// For garbage collection. An array of handles returned by Widget.connect()
// Each handle returned from Widget.connect() is an array of handles from dojo.connect()
this._connects = [];
Having a property of _connects on a custom dijit which inherits from dijit._Widget landed me in trouble. When my.widget.AccountCreator's destroy method was called, the call to dojo.disconnect was throwing an odd looking error:
Result of expression '([dojo._listener, del, node_listener][listener])' [undefined] is not an object
As pointed out by both @neonstalwart and @cb1kenobi (thanks!), there's a simple solution to all this - just use the connect method in dijit._Widget.
this.connect(dijit.byId("accountCreatorDialog"), "hide", "_handleHideDialog");
dijit._Widget's connect method will also take care of automatically disconnect each dojo.connect handle when the widget is destroyed. As a result, you don't need to override the destroy method of your custom widget to clean up any lingering handles.
Have you ever stumbled into an issue like this - are there any other 'common' internal dojo variable names that you've unconsciously clobbered?