Dojo FilteringSelect avoid ajax call onload - dojo

Is there a way to instantiate a FilteringSelect without having it make an ajax call to the server? I have all of the information I need on page load for the object that is currently selected, it makes no sense to have to make another call back to the server for to populate the FilteringSelect with data that I already have. Ideally I'd like to instantiate the FilteringSelect with an object instead of the id.

I have many situations where I have current value available for the FilteringSelect, but not the full store, and like you I was having all these useless ajax calls to get data that I already had.
The problem is that FilteringSelect's set method calls the FilteringSelect's store.get() function, which in the case of dojo/store/JsonRest (which I am assuming is what you use) always issues the ajax call.
In my case, I ended up with my own version of JsonRest which modifies the get method to by-pass the ajax call if the data is already available, which solved the problem.
I cannot think right now of another workable solution.
Find below a template for an extended JsonRest that should help (did not test though):
define(["dojo/_base/declare", "dojo/store/JsonRest"], function(declare, JsonRest){
return declare(JsonRest, {
get: function(id, options){
if (<name for id is known>){
return <name for id>;
}else{
return this.inherited(arguments);
}
});
});
jc

If you already have data, then all you need to do is to create a store and use that with FilteringSelect
For ex: you can create a store like
var stateStore = new dojo.store.Memory({
data: [
{name:"Alabama", id:"AL", timeStamp:"1211753600"},
{name:"Alaska", id:"AK", timeStamp:"1211753601"},
{name:"American Samoa", id:"AS", timeStamp:"1211753602"},
{name:"Arizona", id:"AZ", timeStamp:"1211753603"},
{name:"Arkansas", id:"AR", timeStamp:"1211753604"},
{name:"Armed Forces Europe", id:"AE", timeStamp:"1211753605"},
{name:"Armed Forces Pacific", id:"AP", timeStamp:"1211753606"},
{name:"Armed Forces the Americas", id:"AA", timeStamp:"1211753607"},
{name:"California", id:"CA", timeStamp:"1211753608"},
{name:"Colorado", id:"CO", timeStamp:"1211753609"},
{name:"Connecticut", id:"CT", timeStamp:"1211753610"},
{name:"Delaware", id:"DE", timeStamp:"1211753611"}
], idProperty: "timeStamp"
});
and then assign the store to FilteringSelect
var filteringSelect = new FilteringSelect({
id: "stateSelect",
name: "state",
store: stateStore,
searchAttr: "name"
}, "stateSelect").startup();

Related

Change default Sort order for Arcgis Javascript Feature Table

I would like to have my Feature Table display sorted on the first column when it first appears instead of requiring the user to sort it by clicking on the column header. I have not been able to find a method to do this.
Not sure if this is the best solution, it would be nice to be able to set this in the constructor, but if you call myFeatureTable.grid.set('sort', [{ attribute: ''}]); after the grid fires it's load event, this will sort it before it appears in the UI. For example:
on(myFeatureTable, "load", function(){
myFeatureTable.grid.set('sort', [{ attribute: "<attribute used in first column>"}]);
});
Another method if you have not required dojo/on, you can use the on method of the feature table.
myFeatureTable.on('load', function () {
// Sort on the Name attribute
myFeatureTable.grid.set('sort', [{ attribute: "Name" }]);
})

dojo1.10 Dynamic update of dijit.form.Select

I was trying to asynchronously update a Select field via Memory and ObjectStore. This doesn't work. Setting the data to the Memory object before creating the Select element works fine. Updating the Memory object after creating the Select element doesn't work anymore.
Example code:
require([
"dojo/ready",
"dijit/form/Select",
"dojo/store/Memory",
"dojo/store/Observable",
"dojo/data/ObjectStore",
'dojo/domReady!'
], function(ready, Select, Memory, Observable, ObjectStore, dom){
ready(function() {
var mymem = new Memory();
var myobs = new Observable(mymem);
var mystore = new ObjectStore({ objectStore: myobs });
/* updating memory here works :) */
//mymem.setData([ { id: 2, label: 'qwertz2' }, { id: 3, label: 'qwertz3' } ]);
var s = new Select({
store: mystore
}, 'appsAdminQueueContainer');
s.startup();
/* updating memory here doesn't work :( */
mymem.setData([ { id: 2, label: 'qwertz2' }, { id: 3, label: 'qwertz3' } ]);
});
}
);
Real working example: https://jsfiddle.net/mirQ/ra0dqb63/5/
Is this a bug or is there a solution to be able to update the content of the Select field after creating it - without having to access the Select field directly?
UPDATE
Thank you for your response.
The use of dojo/ready was just a missed leftover while simplifying my code, sorry.
That the use of the ObjectStore is not necessary was not clear to me. Thanks for clearing up.
Okay, the real problem seems to be indeed the last point. I think I have to extend my description.
Updated/extended problem description:
I'm using a grid. At first I was using dojox/grid/DataGrid, but then I switched to dgrid. Everything works well, but I want to use dijit.form.Select as editor for one column. This works also well if the data is static. But in one column I have to read dynamic data from the server. This data comes in JSON format.
First I tried to solve this with the use of dojo/data/ItemFileReadStore - that worked. But it's deprecated and I need to implement a formatter for that column that has to have access to the same JSON data read from the server. I don't have the code for that solution anymore, but it didn't work. I wasn't able to successfully query the data from within the formatter function.
Then I switched to Memory and xhr. The response from the server comes after the Memory object is created (and, as it seems, after creating the Select), so I had to use setData to bring my loaded data in the store. And because the Select is only an editor of a grid, I don't have access to the object itself to be able to re-set the store after updating the data.
I hope my extended description makes my real problem a bit clearer. Thanks in advance for your help!
Mirko
This works for me:
require([
'dijit/form/Select',
'dojo/store/Memory',
'dojo/store/Observable',
], function (Select, Memory, Observable) {
var mymem = new Memory({
data: [{
id: 2,
label: 'qwertz2'
}, {
id: 3,
label: 'qwertz3'
}]
});
var myobs = new Observable(mymem);
var s = new Select({
labelAttr: 'label',
store: myobs
}, 'appsAdminQueueContainer');
s.startup();
myobs.add({ id: 4, label: 'qwerty' });
});
Notable changes:
There's no reason to use dojo/ready in this code. The require callback already waits for modules to load, and as long as this script is at the bottom of the body, there's no need to wait for the DOM to load, either.
There's no need to use a dojo/data store adapter. dijit/form/Select supports dojo/store as well (as of 1.8 if I recall correctly). This might also have been why observation wasn't working. The only difference is labelAttr must be specified on the Select since dojo/store has no concept of a label property.
(Edit) now that I re-read the question, I notice you are calling setData. setData does not fire observers. setData completely resets the store's data, and to reflect that, you would need to actually reset the store on the select entirely (which requires calling setStore, not set('store', ...), if you are using 1.9 or earlier, because Select was never updated properly to support the set API until 1.10).
(Edit #2) Given that the primary reason you are calling setData is due to creating the store before actually having data for it, your case would probably be greatly simplified by using the RequestMemory store implementation from dojo-smore. It basically re-adds the url support that dojo/data/ItemFileReadStore had but dojo/store/Memory didn't.

How to use dojo On with Dojox Searchbox?

I am following this link http://dojotoolkit.org/reference-guide/1.9/dojox/mobile/SearchBox.html and am trying to do the same in my app. The only difference is that I want to use "onSearch" event using "dojo On" but I am not able to read results, query, options that we get by default in the onSearch function.Please help me in solving this problem.
My HTML code:
<input data-dojo-type="dojox/mobile/SearchBox" type="search" placeHolder="Search"
data-dojo-props='store:store, searchAttr: "label", ignoreCase: true, pageSize:2'>
<ul data-dojo-type="dojox/mobile/RoundRectList" jsId="list"></ul>
My JS code:
define(["dojo/has",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/array",
"dojo/dom",
"dojo/dom-class",
"dojo/dom-construct",
"dojo/query",
"dojo/dom-style",
"dojo/dom-attr",
"dojo/on",
"dojo/_base/Deferred",
"dojo/topic",
"dojo/_base/connect",
"dijit/registry",
"dojo/store/Memory",
"dojox/mobile/SearchBox",
"dojo/selector/acme"
],
function(has,declare,lang,array,dom,domClass,domConstruct,query,domStyle,domAttr,on,Deferred,topic,connect,registry,MemoryStore,SearchBox)
{
declare("controllers.SearchController", [], {
started:false,
constructor : function(args) {
WL.Logger.debug("SearchController created");
lang.mixin(this,args);
},
start:function(){
if(!this.started)
{
console.log("i am in SearchController.start");
this.subscription();
this.started = true;
}
},
subscription:function(){
store = new MemoryStore({data: [
{label: "Alabama"},
{label: "Alaska"},
{label: "American Samoa"},
{label: "Arizona"},
{label: "Arkansas"},
{label: "Kansas"},
{label: "Kentucky"}
]});
var searchbox=registry.byId("searchbox");
on(searchbox.domNode,"search",lang.hitch(this,this.onSearch));
},
onSearch: function (results, query, options) {
// this.onSearch = function () {};
console.log(results);
}
});
return controllers.SearchController;
}
);
Also, I am following this link dojox/mobile/SearchBox 'onSearch' event runs twice on webkit
to use the workaround for dojox searchbox. How can I implement it in my case?
You should never try to access widget events through DOM nodes. There is a difference between widgets and DOM nodes, and this is one of them. Also, because dojo/on can only be used with DOM nodes and DOM events, you cannot use it to handle the onSearch event.
Every widget has a on() function that you can use to attach widget event handlers. For example:
searchbox.on("search", lang.hitch(this, this.onSearch));
If the event runs twice, you can try doing something like this (you will probably have to rewrite this in your object oriented design):
var myEventHandler = searchbox.on("search", lang.hitch(this, this.onSearch());
myEventHandler.remove();
According to the API documentation the return value of the on() function is undefined, but this topic its stated that it returns an object containing a remove() function able to remove the event listener.
I don't think it's possible. If you want to retrieve data from your database/webservice, you could use the dojo/store/JsonRest store (RESTful webservices) or you could implement your own store (or fetch the data and put it in a dojo/store/Memory).
Dojo chooses for an abstraction layer upon your data implementation called the store API. The advantages of these are that, because it's an abstraction layer, that you can use your store for multiple purposes (all Dijit widgets, Dojo mobile widgets, ...) work in a similar way that they use a store.
Concerning this part of your question:
I am following this link dojox/mobile/SearchBox 'onSearch' event runs twice on webkit to use the workaround for dojox searchbox. How can I implement it in my case?
I do not think such a workaround is needed. As I wrote in this answer, as long as you have a store specified, SearchBox.onSearch() should be called only once.
In short: just do not apply this workaround, it shouldn't be necessary.
In addition to the event mistake pointed out by Dmitri, there's an issue with the order of execution.
When does Dojo parse your HTML? Do you have parseOnLoad:true in your dojoConfig (or data-dojo-config)?
When the parser reaches data-dojo-type="dojox/mobile/SearchBox", it will try to instantiate a SearchBox widget. Because you have specified store:store in its properties, it will look for a variable called store.
Now, the store variable itself gets instantiated in your SearchController. So you have to make sure that subscription() is called before the parser runs. However, the subscription() method in turn tries to look for a widget called "searchbox". So the parser has to be called before subscription(). As you can tell, this isn't going to work :)
So you have to rewrite the SearchController a bit. For example, you can remove the store:store from data-dojo-props, and let the controller set it in the subscription method:
var store = new MemoryStore({data: [....]});
var searchbox = registry.byId("searchbox");
searchbox.set("store", store);
searchbox.on("search", lang.hitch(this, this.onSearch)); // See Dmitri's answer.

Dojo declarative vs. programmatic creation of Select elements with stores

I'm trying to hook up a Select element with a Dojo store. The Select element is declared in HTML and I'm trying to give it a store in some JavaScript code.
It seems the Dojo documentation recommends against this and is in favor of programatically creating the Select element when using a store. However this is a yellow flag to me because I like to keep creation of HTML elements separate from their behavior. In this case, it would be ideal if I could keep the Select element in HTML and hook up the store in JavaScript.
Is the statement in the Dojo docs really the 'best practice' for this? I'm looking for opinions from experienced Dojo developers as I'm still getting my feet wet with Dojo.
Intuitively one would use select.set("store", store) to assign/change store to a dijit as all widgets are dojo/Stateful, but surprisingly it does not work.
Anyway there is a method select.setStore(store, selectedValue, fetchArgs) which (also surprisingly) is not deprecated and works.
Define dijit/form/Select without a store:
<select id="select1" data-dojo-type="dijit/form/Select"></select>​
Assign a store to it:
require([
"dojo/ready",
"dijit/registry",
"dojo/store/Memory",
], function(
ready, registry, Memory
) {
ready(function() {
var store1 = new Memory({
idProperty: "value",
data: [
{ value: "AL", label: "Alabama" },
{ value: "AK", label: "Alaska" },
{ value: "AZ", label: "Arizona" }
]
});
var select1 = registry.byId("select1");
select1.set("labelAttr", "label");
select1.setStore(store1, "AZ");
});
});
See it in action at jsFiddle: http://jsfiddle.net/phusick/ZmsYV/
Adding some UX sugar to the aforementioned I would create dijit/form/Select disabled with single option e.g. Loading... and its final desired width:
<select
id="select1"
data-dojo-type="dijit/form/Select"
data-dojo-props="disabled:true"
style="width:150px;"
>
<option>Loading...</option>
</select>​
Then I would enable it after calling setStore():
var select1 = registry.byId("select1");
select1.set("labelAttr", "label");
select1.setStore(store1);
select1.set("disabled", false);
See this enhanced version at work: http://jsfiddle.net/phusick/xdDEm/
Debugging bad store data/definitions can get pretty nasty when doing so declaratively. Additionally, you may run into strange annoyance when trying to create multiple of the same widget following a declaratively built select/store combination. For example (pseudocode):
<div dojotype="dojox.data.QueryReadStore" url="someurl/blah.do" jsId="mystore"/>
<select dojotype="dijit.form.FilteringSelect" store="mystore">
</select>
The would in theory do what you want by binding mystore to the select, however if you were to create multiple of this widget, you'd have an id conflict with "mystore." As a workaround you'd have to do something like jsId="${id}_mystore" for both the jsId and the store's id.
One option if you would like to keep a declarative behavior is to have attachpoints for both your store and your select, then you can simply call selectwidget.set("store",mystore) after initialization.

Using dijit.InlineEditBox with dijit.form.Select

I'm trying to use a dijit.form.Select as the editor for my dijit.InlineEditBox. Two problems / unexpected behavior seem to occur:
Inconsistently, the InLineEditBox doesn't have the initial value set as selected
Consistently, after selecting a choice, the value that should be hidden is shown instead of the label.
The width isn't set to 130px
Here's working code: http://jsfiddle.net/mimercha/Vuet8/7/
The jist
<span dojoType="dijit.InlineEditBox" editor="dijit.form.Select"
editorParams="{
options: [
{label:'None',value:'none'},
{label:'Student',value:'stu'},
{label:'Professor',value:'prof',selected:true},
],
style:'width:1000px;',
}"
editorStyle="width: 1000px;"
>
</span>
Any help is greatly appreciated! Thanks!
Okay, after a few MORE hours struggling with the mess that is dijit.InlineEditBox, I think I have the solution to the remaining issue (#2).
EDIT: My first solution to #2 is still flawed; the implementation at http://jsfiddle.net/kfranqueiro/Vuet8/10/ will never return the actual internal value when get('value') is called.
EDIT #2: I've revamped the solution so that value still retains the real (hidden) value, keeping displayedValue separate. See if this works better:
http://jsfiddle.net/kfranqueiro/Vuet8/13/
First, to recap for those who weren't on IRC:
Issue #1 was happening due to value not being properly set as a top-level property of the InlineEditBox itself; it didn't pick it up properly from the wrapped widget.
Issue #3 was happening due to some pretty crazy logic that InlineEditBox executes to try to resolve styles. Turns out though that InlineEditBox makes setting width particularly easy by also exposing it as a top-level numeric attribute. (Though IINM you can also specify a percentage as a string e.g. "50%")
Now, issue #2...that was the killer. The problem is, while InlineEditBox seems to have some logic to account for widgets that have a displayedValue attribute, that logic is sometimes wrong (it expects a displayedValue property to actually exist on the widget, which isn't necessarily the case), and other times missing entirely (when the InlineEditBox initializes). I've worked around those as best I could in my own dojo.declared extensions to InlineEditBox and the internal widget it uses, _InlineEditor - since generally it's a good idea to leave the original distribution untouched.
It's not pretty (neither is the underlying code I dug through to understand and come up with this), but it seems to be doing its job.
But man, this was rather interesting. And potentially pertinent to my interests as well, as we have used this widget in our UIs as well, and will be using it more in the future.
Let me know if anything backfires.
hm...
<span dojoType="dijit.InlineEditBox" editor="dijit.form.Select"
editorParams="{
options: [
{label:'None',value:'none'},
{label:'Student',value:'stu'},
{label:'Professor',value:'prof',selected:true},**<<<<** and this comma is for?
],
style:'width:1000px;',**<<<<** and this comma is for?
}"
editorStyle="width: 1000px;"
>
</span>
Also, when using dijit.form.Select, selected value is not attr "selected" but value.
And if you enter prof inside <span ...blah > prof </span> than your proper selected option will be selected ;)
Dijit select checks for VALUE, not attr.
This may be fixed in recent Dojo - see http://bugs.dojotoolkit.org/ticket/15141 - but using 1.7.3 I found this worked:
In my app directory, at the same level as dojo, dijit and dojox, I created a file InlineSelectBox.js which extends InlineEditBox with code to set the HTML on the associated domNode from the value of the Dijit, and which wires up that code to the onChange() event:
define(["dijit/InlineEditBox",
"dijit/form/Select",
"dojo/on",
"dojo/_base/declare",
"dojo/_base/array"
],
function(InlineEditBox, Select, on, declare, array){
return declare(InlineEditBox, {
_setLabel: function() {
array.some(this.editorParams.options, function(option, i){
if (option.value == this.value) {
this.domNode.innerHTML = option.label;
return true;
}
return false;
}, this);
},
postMixInProperties: function(){
this.inherited(arguments);
this.connect(this, "onChange", "_setLabel");
},
postCreate: function(){
this.inherited(arguments);
this._setLabel();
}
});
});
Then, in my view script:
require(["dojo/ready",
"app/InlineSelectBox",
"dijit/form/Select"
],
function(ready, InlineSelectBox, Select){
ready(function(){
// Add code to set the options array
var options = [];
// Add code to set the initial value
var initialValue = '';
var inlineSelect = new InlineSelectBox({
editor: Select,
editorParams: {options: options},
autoSave: true,
value: initialValue
}, "domNodeToAttachTo");
});
});
I was dealing with this situation a few months ago, and not finding a resolution i made my own algorithm.
I put a div with an event on Onclick that build programatically a Filtering Select on that div with the store i want to use.
function create(id,value){
var name = dojo.byId(id).innerHTML;
dojo.byId(id).parentNode.innerHTML = '<div id="select"></div>';
new dijit.form.FilteringSelect({
store: store,
autoComplete: true,
invalidMessage:"Invalid Selection",
style: "width: 80px;",
onBlur: function(){ },
onChange: function(){ },
required: true,
value: value,
disabled: false,
searchAttr: "name",
id: "status"+id,
name: "status"
},"select");
dijit.byId('status'+id).focus();
}
I used the onBlur event to destroy the widget and the onchange to save by xhr the new value.
The focus is below because the onBlur was not working properly.
note: the function is not complete.