Dijit widgets provide the ability to write custom setters and getters, whose logic is executed when calling the set
and get
methods. dijit/_WidgetBase
also provides a _set
method, which is very important when writing widgets, but can cause a bit of confusion due to its name.
set
The set
method provides a public API for setting one or more properties on a widget instance.
// Set a single property "foo" to the value "bar"
myWidget.set("foo", "bar");
// Set multiple property values at once
myWidget.set({
foo: "bar",
baz: "qux"
});
Using the set
method when updating widget properties is important, as it will in turn call any custom setter method defined for that property. Custom setter methods are defined following the pattern _setFooAttr
, where “foo” is the name of the property:
declare(_WidgetBase, {
foo: "",
_setFooAttr: function (value) {
// Perform custom logic, and update the foo property
}
});
Note that in addition to performing custom logic, the custom setter is typically also responsible for updating the corresponding property’s value — Dijit doesn’t do this automatically when a custom setter method is defined. This allows the custom setter to potentially transform the incoming value before updating the property.
Your first thought might be to simply update the value directly (e.g. this.foo = value;
), but there is one major flaw to that approach. dijit/_WidgetBase
inherits from dojo/Stateful
, which also provides the watch
method. However, it is incapable of notifying watchers of direct property updates. In other words, if we take this approach, watchers registered for this property will never fire!
_set
In a pure dojo/Stateful
instance, set
is responsible for notifying watchers, but in the case of Dijit, as we’ve already seen, it is already responsible for delegating to our custom setter in the first place, so there needs to be a distinct API for notifying watchers. That’s where _set
comes in.
As its underscore-prefixed name suggests, _set
is an internal method intended to be used from within _WidgetBase
extensions. Its purpose is quite simple – it updates the value of the indicated instance property, and also fires any watchers for that property.
Thus, the correct way of properly updating a property within a custom setter is to call _set
:
_setFooAttr: function (value) {
// Perform custom logic...
// ...and update the instance property
this._set("foo", value);
}
Putting it all together
Here is an example featuring a widget with a custom setter for the foo
property. We instantiate the widget and add a watcher so we can see how _set
interacts with it.
require([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dojo/domReady!"
], function (declare, _WidgetBase) {
var MyWidget = declare(_WidgetBase, {
foo: "",
_setFooAttr: function (value) {
console.log("Setting value of foo to " + value);
this._set("foo", value);
}
});
var widget = new MyWidget().placeAt(document.body);
widget.startup();
widget.watch("foo", function (property, oldValue, value) {
console.log("Watcher for 'foo' fired, changing property value from " +
oldValue + " to " + value);
});
widget.set("foo", "bar");
});
Upon running this example, we will see the following console output:
"Setting value of foo to bar"
"Watcher for 'foo' fired, changing property value from to bar"
If we had only performed this.foo = value
in the setter instead, the second line would not appear, since the watcher would never fire.
In summary, _set
is a crucial part of writing custom setters for widgets, while set
is the public API responsible for firing these custom setters in the first place.