Newbie alert: please go easy on me
I have successfully populated a ComboBox from a json file, but when I try it with a MultiSelect it does not work.
Working code:
dojo.require("dijit.form.MultiSelect");
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.form.ComboBox");
...
<div dojoType="dojo.data.ItemFileReadStore"
jsId="coffeeStore" url="./coffee.json"></div>
...
<select name="coffee" dojoType="dijit.form.ComboBox"
store="coffeeStore" searchAttr="name">
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.form.ComboBox");
...
<div dojoType="dojo.data.ItemFileReadStore"
jsId="coffeeStore" url="./coffee.json"></div>
...
<select name="coffee" dojoType="dijit.form.ComboBox"
store="coffeeStore" searchAttr="name">
If I change ComboBox to MultiSelect in the select, it does not work. What am I missing?

So it doesn't look like
So it doesn't look like MultiSelect is store-aware. The description it provides in the API says: Wrapper for a native select multiple="true" element to interact with dijit.form.Form ... I wrote it with no dojo-data thoughts in mind in fact, though it would be fairly easy to manually populate via the store by creating option nodes and adding them to the domNode:
onItem: function(item){
var option = dojo.doc.createElement('option');
option.innerHTML = option.value = coffeeStore.getAttribute(item, "name");
dijit.byId("multiSelWidget").domNode.appendChild(option);
},
query: "*" // or something
});
hope this helps. it might be good for MultiSelect to support dojo.data like the rest of Dijit, but again it was written with solving a single degradable usecase / limitation of dijit.form.Form ...
yeah... u are missing... :)
Unfortunately although one could expect MultiSelect widget is not datastore enabled. :(
There is a way to do it. It is a bit hackish and dirty. It would be much nicer if MultiSelect would have native store functionality as ComboBox or FilteringSelect.
In html:
</select>
In header:
// Create new store. I'm using PHP to generate data. Could be anything else that would return data in requested format
var store = new dojo.data.ItemFileReadStore({url: '/index.php/stores/get/vacancyLevel'});
// Force store to load. We can't wait on it. :)
store._forceLoad();
// Define return handler.
var gotItems = function(items, request){
// Get reference to select defined in html
var ms = dojo.byId('vlevel');
// Loop results
for (var a = 0; a < items.length; a++) {
// Append new element to select defined in html and store reference to it
var n = ms.appendChild(document.createElement('option'));
// Set values to reference option node
// vltype and name are arbitrary and should correspond to attributes used
n.value = items[a].vltype;
n.innerHTML = items[a].name;
}
};
// Fetch all items
store.fetch({onComplete: gotItems});
// turn any non-dojoType selects into widgets programatically:
dojo.query("select").forEach(function(n){
if(!dijit.byNode(n)){
var foo = new dijit.form.MultiSelect({
},n);
}
});
});
Thanks for the help. I will
Thanks for the help. I will try it. As a newbie, it is not confidence inspiring that this is not noted in the documentation. I struggled with this for awhile, assuming I was at fault. It makes me wonder what other things are missing that will cause me trouble.
hmmmm
for what it's worth, it was "noted" in the documentation that it was a "wrapper around a native select multiple="ture" element" to work in a dijit.form.Form, so while not overly explicit about the fact, it seemed clear. Perhaps some page somewhere needs further explanation for this one-off. Do you have a link where you'd suggest such information appear? In fact, I believe you can login the API pages via this same login and leaves comments directly attached. This seems like a perfect note to add on a page talking about MultiSelect.
The presence of a "store" attribute (and usually a "query" attribute) is the indication some component supports datastores, and to be honest I think MultiSelect is the _only_ non dojo-data ready form data-dijit (well, button's don't support dojo.data either ;) ). The difficult part is documenting which functions actually get used versus the ones mixed into _Widget by other widgets, as both appear in the API pages ...
http://api.dojotoolkit.org/jsdoc/dijit/HEAD/dijit.form.MultiSelect
As a fallback, you can look at the test file for any widget, there is at least one per component. If it supports data stores, there is a physical test somewhere to ensure it remains working:
http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/tests/form/test...
Oddly, the is a DojoX form "CheckedMultiSelect" that doesn't support dojo.data either:
http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/form/tests/test...
Regardless, if a widget supports something, there is a test somewhere to prove it :)
The comments above are the first request for dojo.data-store enabled MultiSelect I've heard. The reason the widget is there in the first place is because someone filed an enhancement request at http://trac.dojotoolkit.org wanting to make a multi-select of their own report it's values in a dijit.form.Form, so I wrote the Simple-degradable-Select and dumped it in dojox. If you'd like to see features or support added to a component, please, file a ticket, it's the only way we know what people want. It seems an entirely valid request for MultiSelect to allow datastore access.
Wow..thanks your response
Wow..thanks your response goes a long way to restoring my confidence!
@dante
I can't make you example work. :( (without making few changes :))
When removed
query: "*" // or somethingI've got error getAtribute is not a function and indeed in ReadAPI http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-... can't find getAtribute but there is method getAttributes. Nevertheless I guess that you made lapsus calami and that it should read getValue instead getAttributes.Here is working example (tested in FireFox3 on Ubuntu Hardy):
// Create new store. I'm using PHP to generate data. Could be anything else that would return data in requested format
var store = new dojo.data.ItemFileReadStore({url: '/index.php/stores/get/vacancyLevel'});
store.fetch({
onItem: function(item){
var option = dojo.doc.createElement('option');
option.innerHTML = store.getValue(item, "name");
option.value = store.getValue(item, "vltype");
dijit.byId("vlevel").domNode.appendChild(option);
}
});
<!-- html -->
<select id="vlevel" multiple="true" name="vlevel"
dojoType="dijit.form.MultiSelect"
style="height:72px; width:30em; border:1px solid #ececec;">
</select>
Btw. I find that Dojo documentation OK. Along with API, support and forums it is relatively easy to start using Dojo.
widget SelectMulti
Adding onLoad event on each page is not such elegant solution so I came up with more generic solution: widget based on MultiSelect using any given store. It needs some polishing for sure and to use it one should change walras.Form accordingly. Same applies to the link of the actual store.
dojo._hasResource["walras.Form.SelectMulti"] = true;
dojo.provide("walras.Form.SelectMulti");
dojo.require("dijit.form.MultiSelect");
dojo.require("dijit._Templated");
dojo.declare("walras.Form.SelectMulti", dijit.form.MultiSelect, {
store: '',
name: '',
dataObject: null,
counter: 1,
onItem : function(item) {
var option = dojo.doc.createElement('option');
option.innerHTML = this.dataObject.getValue(item, "name");
option.value = this.dataObject.getValue(item, "vltype");
this.domNode.appendChild(option);
},
loadStore: function() {
this.dataObject._forceLoad();
this.dataObject.fetch({
onItem: dojo.hitch(this, 'onItem')
});
},
startup: function(){
if(dojo.isString(this.store)){
this.dataObject = dojo.getObject(this.store)
this.loadStore();
};
}
});
}
And than in html:
url="/index.php/stores/get/vacancyLevel"></div>
<div id="vlevel" multiple="true" name="vlevel"
dojoType="walras.Form.SelectMulti" store="vlevelStore"
style="height:72px; width:30em; border:1px solid #ececec;">
</div>
And last but not least in head of page:
dojo.require("dojo.data.ItemFileReadStore");
one more revison :)
I am novice to dojo and JavaScript. Due to my luck of knowledge and understanding I didn't know how to make code generic.
Method onItem is renamed to addOption. Two lines in this method are changed:
option.value = this.dataObject.getValue(item, "vltype");
are changed to:
option.value = this.dataObject.getIdentity(item);
In this way you don't have to change code and use names as they appear in each new store but just set identifier and label accordingly.
In startup method line
if(dojo.isString(this.store)){is changed toif('' != this.store){since store is always string which would cause error if store name is not given in markup.Finally here is entire code:
dojo._hasResource["acme.form.SelectMulti"] = true;
dojo.provide("acme.form.SelectMulti");
dojo.require("dijit.form.MultiSelect");
//dojo.require("dijit._Templated");
dojo.require("dojo.dnd.Source");
dojo.declare("acme.form.SelectMulti", dijit.form.MultiSelect, {
store: '',
dataObject: null,
addOption : function(item) {
var option = dojo.doc.createElement('option');
option.innerHTML = this.dataObject.getLabel(item);
option.value = this.dataObject.getIdentity(item);
this.containerNode.appendChild(option);
},
loadStore: function() {
this.dataObject._forceLoad();
this.dataObject.fetch({
onItem: dojo.hitch(this, 'addOption');
});
},
startup: function(){
if('' != this.store){
this.dataObject = dojo.getObject(this.store);
this.loadStore();
}
}
});
}
latest changes
http://bugs.dojotoolkit.org/ticket/7245
The custom MultiSelect.js
The custom MultiSelect.js attached to the ticket http://bugs.dojotoolkit.org/ticket/7245 is missing "name='${name}'" in the templateString.
I realized this when I saw that my form when submitted was not submitting selected values in the MultiSelect list as part of the request. The fix I did was to change the templateString in the MultiSelect.js as follows -
Earlier
=====
templateString: "<select multiple='true' dojoAttachPoint='containerNode,focusNode' dojoAttachEvent='onchange: _onChange'></select>",
Fix
===
templateString: "<select multiple='true' name='${name}' dojoAttachPoint='containerNode,focusNode' dojoAttachEvent='onchange: _onChange'></select>",
Also, I added a new attribute 'selected' (type Array) to allow default selection of options when the list is rendered. Did the following -
[1] Added this to the attribute declaration -> selected: null
[2] Added following lines to the addOptions() method -
// Allow default selected values to be specified while creating the MultiSelect widget.
if (this.selected) {
this.setValue(this.selected);
}
If anyone else was able to use this custom widget without including this fix, please post your ideas.