Consistent Interaction with Stateful Objects in Dojo

By on May 4, 2010 12:02 am

Dojo 1.5 introduces a new paradigm for consistent interaction with stateful objects like widgets. Stateful objects now follow a pattern of using get() and set() methods for accessing and setting named properties. Following this paradigm, to get a named property from a widget, we now use:

widget.get("checked");

And to set a named property we do:

widget.set("checked", true);

This essentially supersedes the widget system’s attr() method, providing more readable function names that don’t require branching on variable argument length, and are more easily overridden. The attr() will remain in Dojo 1.5, but now delegates to get() and set(). The use of get() and set() is recommended over attr() now.

Introducing dojo.Stateful

Dojo also introduces a new constructor for creating stateful objects with the dojo.Stateful module. This module provides simple default get() and set() implementations as well as the third complementary method, the watch(). The watch() design is based on the Mozilla’s watch function, and provides an easy mechanism for monitoring state changes. Using dojo.Stateful, we can now create objects that can be mutated, read, as well as monitored:

var obj = new dojo.Stateful({
  price: 9.99
});

First, we created a new Stateful object with a property price set to 9.99. Now, we can monitor that object for changes:

obj.watch("price", function(){
  console.log("price changed to " + this.get("price"));
});

Later if the property is changed:

obj.set("price", 6.99);

This will fire the watch callback function that prints out the new price.

The watch function returns an object that can later be used to discontinue a watch by calling the unwatch() method. For example:

watchHandle = obj.watch("price", callback);
...
// no longer want to watch:
watchHandle.unwatch();

Possibilities and future directions using Stateful

While widgets in Dojo 1.5 will only provide get() and set() methods (not watch()), we are hoping to have dijit._Widget subclass dojo.Stateful in 1.6 providing a convenient and consistent approach to monitoring widget property changes as well as other objects. We will then be able to use the watch method on any widget.

We are also considering a new Dojo Data design where data items would also follow this interface, allowing even broader consistency in a uniform interface for accessing and monitoring stateful objects, whether they are items from a data store, widgets, or other user objects that extend dojo.Stateful.

One of the key motivations for this design is that it would ultimately enable building functionally reactive “live” templating engines or data-bindings on top of Dojo. The concepts of functional reactive design (or data-bindings) have been demonstrated in other projects like Flex, Flapjax, and Fin. Eventually we will be able to write templates like:

${obj.get("foo")}

And the templating engine could determine that it needs to call the watch method to monitor object obj and it could automatically update the rendered view when the object changes. We can also create data bindings between different objects (changes in an object would get automatically synchronized to another object). Projects like Flapjax and Fin that have used this approach are clever but have very limited use because they require an interface that doesn’t match with common existing components. By following a consistent pattern throughout Dojo, we can enable this type of live templating in a way that really is useful. Again, these are future ideas, not yet implemented, but the consistent interface makes this very doable.

For now you can begin to use get() and set() methods on all widgets in Dojo 1.5, and create your own watchable objects with dojo.Stateful that can easily be monitored for state changes.

Comments

  • Ken F.

    I have a few questions.

    1. When you say that get and set are more easily overridden, what do you have in mind? I’ve never overridden attr directly, only implemented _getSomethingAttr or _setSomethingAttr methods – is this paradigm also going to be changing for any reason?

    2. RE the idea of ${obj.get(“foo”)} in templates:
    a. Is this essentially aiming for a more accessible shorthand alternative to attributeMap? Would attributeMap still exist/work?
    b. Wouldn’t this require making the string substitution logic employed by the templating process significantly more complex? (Actually hadn’t it been /simplified/ not that long ago?)

    3. Any idea what’s in mind for the data APIs yet? Would this somehow fit into the write/notification APIs or are you eventually plotting more or less a full rewrite? If the latter, how difficult will migration be for people who’ve written custom data store implementations?

    Thanks for all the great articles lately :)

  • Les

    I wanted to add that according to the Stateful.js code the price watch example could be modified:

    obj.watch(“price”, function(){
    console.log(“price changed to ” + this.get(“price”));
    });

    obj.watch(“price”, function(name, oldValue, newValue){
    console.log(name + ” changed from ” + oldValue + ” to ” + newValue);
    });

  • @Ken:
    1. The overridable individual getter and setter methods (like _setSomethingAttr) will remain in widgets. This functionality doesn’t exist dojo.Stateful, as it is intended to just be a lightweight base class.
    2. attributeMap will stay around as well, but this is for internal mapping of properties to attributes, not for external users of stateful objects to map properties to ad-hoc templating conversions. Also, this is designed for new potential template engines that do expression evaluation (not just string substitution) and does not affect the actual templating algorithm, it only gives the template engine a way to look at expressions and register for notifications so that it can determine when it needs to reevaluate
    3. I am working on a prototype for a new data API which will indeed converge with the get/set/watch pattern. This is by no means guaranteed, but we are hoping to have a prototype to play with in a branch for consideration for inclusion in 1.6 or 2.0. We certainly would have adapters for both old to new API conversion and new to old API conversion to ensure backwards compatibility.

  • Luis

    Love the stateful idea. Reminds me of the propertychange event handling from IBM’s Visual Age years ago. The cool thing was that you could easily wire up widgets to properties of a bean and sync both ways. Made it simple to do client side model-view separation.

    Might be interesting to see a stateful object connected to an HTML gui and synced to a server via comet with minimal effort.

  • Vladimir

    >I am working on a prototype for a new data API

    This project if done properly will have a huge impact for web application development.
    I have exactly the same vision as Luis on this matter.
    So please make it soon as possible and don’t forget keep us posted :)

    Best regards

  • +1 on this effort

    We (at Redfin) home-brewed our own code that does something very similar. The main goal was to represent a given object only once on the client, and to have multiple widgets watching for changes to that object. Each property “foo” has a triad of methods: getFoo(), setFoo(), and onChangeFoo(). We use dojo.connect to watch for changes to individual properties and to automatically refresh the display on widgets. It’s functional and we’ve been using it for several months now. But I for one would love to stop having to maintain our own code for this and use something standard, assuming it meets our needs, is stable, etc.

    BTW, as a further step, we’ve also written code to serialize our server-side (Java) objects, serialize them into JSON for sending over the wire, and reconstitute them on the client-side, and “hydrate” them by slapping all the get/set/onChange methods onto them. This has made it much easier to write pages end-to-end. We no longer need to write custom serialization code. We have standard data objects on the server and a parallel set of standard data objects on the client.

    One of the major challenges in this design is the fact that Java objects can be connected as a graph (not a tree) and Javascript objects can be connected as a graph (not a tree), but in between we’re using JSON, and by default JSON doesn’t represent trees very well. We needed to do something more in order to detect and serialize object references, and to honor them on the client-side. My esteemed colleague Sasha Aickin did the lion’s share of this work, based to some degree on other JSON serialization/deserialization libraries we found on teh interwebs.

    We’re still fine-tuning our design, and the issues we’re looking into now have to do with performance. The simple thing to do is to just send all your objects (and child objects, and grandchild objects…) to the client, along with all their properties. But, depending on your situation, this can spiral out of control. As Sasha says: performance is where elegant designs go to die. So we’re looking at different designs/patterns that allow the developer to easily cap the quantity of data. This is actually at two levels: 1. the data fetched from the DB into Java, and 2. the data serialized by Java and sent to the client to be used in Javascript. This is an ongoing effort.

    At any rate, we support your effort and we’ll keep an eye out for news.

    cheers,

    –S

  • Corey Alix

    +5 years…has reactive functionality ever make it into dojo? Does dojo(x) have a reactive module distinct from the dojo primitives (promise+all+on+throttle+…)?