Login Register

Dojo.data Notification events and easy passing of store references to generic event handlers.

A while ago I was working with another committer in the dojo community on usage of the dojo.data notification APIs. He had hit a problem where it would have been really convenient if the dojo.data Notification functions onSet(), onNew(), and onDelete(), also passed in a reference to the store.

This request came up after the API had been solidified and we were very wary of making changes to it that would affect dijit or others dependant on the interfaces. And yet, his use-case/desire to have that store reference passed in was perfectly reasonable. While just fiddling around recently, I realized dojo already provided an excellent mechanism that would allow you to pass in a store reference without changing the API signature that dojo.data defines for its handlers.

It’s basically a perfect use for the dojo.partial() api. When I first saw dojo.partial, I found it to be a strange function since it let you pre-pend parameters into a function call. But, after having used complex widgets sich as dojox.Grid, I have learned to appreciate what it can do and how it can make development simpler. So, see below for some example code that shows using dojo.partial with a generic onSetEvent handler in order to pass in store references automatically when the notification functions are invoked.

//Very basic datasets for constructing a couple instances of ItemFileWriteStore.
var set1 = {

label: "name",
identifier: "name",
items: [

{

name: "item1",
attr1: "val1",
attr2: "val2"

},
{

name: "item2",
attr1: "val3",
attr2: "val4"

},
{

name: "item3",
attr1: "val5",
attr2: "val6"

}

]

};
var set2 = {

label: "name",
identifier: "name",
items: [

{

name: "other_item1",
attr1: "val1",
attr2: "val2"

},
{

name: "other_item2",
attr1: "val3",
attr2: "val4"

},
{

name: "other_item3",
attr1: "val5",
attr2: "val6"

}

]

};

//Create some stores.
var store1 = new dojo.data.ItemFileWriteStore({data: set1});
var store2 = new dojo.data.ItemFileWriteStore({data: set2});

//A very basic onSet function that has an extra parameter in the beginning, the store reference.
function onSetEvent(store, item, attribute, oldValue, newValue) {

alert ("Item: [" + store.getLabel(item) + "] was changed. Attribute: [" + attribute + "] old value: [" + oldValue + "] new value: [" + newValue + "]");

}

//Now, connect our change event listener functions to the store notification API.
dojo.connect(store1, "onSet", dojo.partial(onSetEvent, store1));
dojo.connect(store2, "onSet", dojo.partial(onSetEvent, store2));

//Define an onComplete hander. This too we will use dojo.partial to set the store reference.
function onComplete(store, items, request){

if (items) {

var i;
for (i = 0; i < items.length; i++) {

store.setValue(items[i], "attr1", "FooBar!");

}

}

}

//Now call a couple fetches. These will call the callbacks with the right store reference. The callback will then change some values,
//which triggers the onSet API of dojo.data.Notification. Since we used dojo.partial when we connected to the onSet API, we will get
//a reference to our store easily in a 'generic' function without relying on the scope of when that function was declared.
store1.fetch({query: {name:"*"}, onComplete: dojo.partial(onComplete, store1)});
store2.fetch({query: {name:"*"}, onComplete: dojo.partial(onComplete, store2)});

The above code adds in very little extra code to get the behavior desired. Basically, it just changes the connect call slightly to produce the desired passing of the right store reference on an Notification event from the store.