Login Register

Widget.attr()

Dojo 1.2 will sport a nice API standardization for widgets. Widget.attr() is now the standard interface for setting/getting all widget attributes. For example:

// set title
myTitlePane.attr('title', 'hello world');
// find out if button is disabled
var dis = myButton.attr('disabled');
// set to the current date
myDateTextBox.attr('value', new Date());

It also supports a hash API like dojo.attr(), for setting multiple attributes:

myInput.attr({ tabIndex: 3, disabled: true, value: 'hi'});

Notes for widget developers:

The first thing to think about as a widget developer is that all the documentation for an attribute needs to go next
to the attribute definition, even when you need special documentation about how attr() is performing for that
widget.

// value: Date
//     The date picked on the date picker, as a Date Object.
//     When setting the date on initialization (ex: new DateTextBox({value: "2008-1-1"})
//     or changing it (ex: attr('value', "2008-1-1")), you  can specify either a Date object or
//     a string in ISO format

The second thing is that when writing or extending a widget now you need to think of a "holy trinity" for each widget attribute:

  1. initialization
  2. setter
  3. getter

Some attributes can only be specified at initialization time, but for most of them, they can be changed after initialization, and users can always get the
value at any time, which means that some of the paradigms we've been using up 'till now need to be changed. For example, you might have had a template
like this:

<button>${label}</button>

That's compact and new myButtonWidget({label: 'hi'}) works fine, but myButtonWidget.attr('label', 'bye') doesn't.

So, instead, you should be supporting this through the enhanced attributeMap in the 1.2 release.
You should think of attributeMap as a binding from widget attribute to DOM nodes. Previously
in 1.1 it could only map widget attributes to DOM node attributes, but now in 1.2 it can map to
innerHTML (like above) too.

So your attributeMap should map from the widget attribute to the DOM node innerHTML. You can
see this in action for TitlePane:

attributeMap: dojo.mixin(dojo.clone(dijit.layout.ContentPane.prototype.attributeMap), {
        title: {node: "titleNode", type: "innerHTML" }
}),

(the fancy mixin stuff is so TitlePane's attributeMap has everything that ContentPane has,
plus this additional command).

It also supports class attributes like iconClass, see Menu for an example of both in action:

attributeMap: dojo.mixin(dojo.clone(dijit._Widget.prototype.attributeMap), {
        label: {node: "containerNode", type: "innerHTML"},
        iconClass: {node: "iconNode", type: "class" }
}),

Custom setters/getters

When you have an attribute where setting/getting it is more complicated than attributeMap can
handle, you need to write custom getters/setters for it. The naming convention is _setFooAttr() and
_getFooAttr(). attr() will automatically detect and call these custom setters.

Custom setters are quite common. Usually you don't need a custom getter (as the default action
for attr('foo') is to access Widget.foo), but for something like Editor where it's impractical to constantly
keep Editor.value up to date, writing a custom _getValueAttr() accessor makes sense.

postCreate()
The custom setters listed above, plus every entry in attributeMap, is applied during
widget creation (in addition to whenever someone calls attr('name', value)).
So, much of the code you previously had in postCreate() can go away.

Note that the application happens after buildRendering() but before postCreate(), so
you need to make sure that none of that code is dependent on something that happens
in postCreate(), or later. This in particular is an issue for any widgets that depend on timeouts
for setup, which need to have special code to handle when _setDisabledAttr() etc. is
called during startup.

Anyway, all this code is available in trunk now so I encourage you to take it for a test drive.
We are still working out some kinks so now's a great time to give feedback on it, to make sure
that the 1.2 release is solid. Thanks!

Bill

Widget.attr() - how do I remove?

Looks great so far...

But, How do I remove an attribute?

--
Happy Hacking,
Gaurav
http://sf.net/projects/dwt
--------------------------------

what about dojox.widget.Toaster.setContent ?

Hello,

If setContent is depracted, how to do with the Toaster which receive 3 parameters value, nature of the message and duration ?

Arnaud.

from 1st post...

[cut]
It also supports a hash API like dojo.attr(), for setting multiple attributes:

myInput.attr({ tabIndex: 3, disabled: true, value: 'hi'});
[/cut]

which attribut ?

I agree you I can do a setContent and setDisabled for the same field in one line.
In that case this is 2 attributes with each 1 value to update
attr({Content : "content", disabled : true}

In my case this one attribute, the attribute content with 3 value to update
setContent(value1, value2, value3)

So my question is maybe just what are the name of the 3 attributes which are updated with the function setContent for the toaster.

Arnaud.

the dojox.widget.Toaster has

the dojox.widget.Toaster has it's own implementation of setContent, and is not part of Dijit. .attr() provides attribute setting in Dijit widgets and the dijit framework, but the setContent function in Toaster overrides that. This is an API inconsistency, and for now "just a fact of life" ... So the dojox.widget.Toaster's setContent is NOT deprecated (yet), though should be reworked to use .attr(), though it introduces an issue because the setContent in toaster is a different API than setContent in ContentPane/Dijit all together.

One little tweak

Hi Bill,

Seems like a small enhancement to attributeMap to permit mapping to an attribute of a different name, on the target node.

e.g.

attributeMap :{
minVal: {node: "text1", type="attribute", attribute:"value"},
maxVal: {node: "text2", type="attribute", attribute:"value"},
}

That's the only way I could have two attributes on my widget mapped to the "value" attributes on two nested elements, right? Apart from writing setters and getters I mean.

Hugh