dojo1.10 Dynamic update of dijit.form.Select - dojo

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.

Related

OpenUI5 sap.m.Input Currency Formatting

This looks to be answered many different times but I can't seem to get it working with my implementation. I am trying to format and limit the data in a sap.m.Input element. I currently have the following:
var ef_Amount = new sap.m.Input({
label: 'Amount',
textAlign: sap.ui.core.TextAlign.Right,
value: {
path: '/amount',
type: 'sap.ui.model.type.Currency'
}
});
The first problem is that it kind of breaks the data binding. When I inspect the raw data (with Fiddler) submitted to the server it is an array like this:
"amount": [1234.25,null]
The server is expecting a single number and as such has issues with the array.
When I use the following, the binding works as desired but no formatting is performed.
var ef_Amount = new sap.m.Input({
label: 'Amount',
textAlign: sap.ui.core.TextAlign.Right,
value: '{/amount}'
});
The second problem is that the data entered is not limited to numbers.
I have tried using sap.m.MaskedInput instead but I don't like the usage of the placeholders because I never know the size of the number to be entered.
And lastly, it would be nice if when focus is placed on the input field, that all formatting is removed and re-formatted again when focus lost.
Should I be looking into doing this with jQuery or even raw Javascript instead?
Thank you for looking.
the array output is a normal one according to documentation. So you need to teach your server to acccept this format or preprocess data before submission;
this type is not intended to limit your data input;
good feature, but ui5 does not support this, because the Type object has no idea about control and it's events like "focus" it only deals with data input-output. So you have to implement this functionality on your own via extending the control or something else.
I would suggest using amount and currency separately. It's likely that user should be allowed to enter only valid currency, so you can use a combobox with the suggestions of the available currencies.
So, after much work and assistance from #Andrii, I managed to get it working. The primary issue was that onfocusout broke the updating of the model and the change event from firing. Simply replacing onfocusout with onsapfocusleave took care of the issues.
The final code in the init method of my custom control:
var me = this;
var numberFormat = sap.ui.core.NumberFormat.getCurrencyInstance({maxFractionDigits: 2});
me.addEventDelegate({
onAfterRendering: function() {
// for formatting the figures initially when loaded from the model
me.bindValue({
path: me.getBindingPath('value'),
formatter: function(value) {
return numberFormat.format(value);
}
});
},
onfocusin: function() {
// to remove formatting when the user sets focus to the input field
me.bindValue(me.getBindingPath('value'));
},
onsapfocusleave: function() {
me.bindValue({
path: me.getBindingPath('value'),
formatter: function(value) {
return numberFormat.format(value);
}
});
}
});

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.

sencha touch - custom html template ported from another framework

Previous attempt at this app was done in jqtouch and this effect worked perfectly. Im having a really hard time wrapping my head on how best to do this with sencha touch.
My situation is best described in this image
This is just one item that should populate a carousel so reusing it with different data is paramount (no hard coded html).
thank you
Finally solved it thought I should update it here
Ext.define('mobuy.view.myCarousel', {
extend: 'Ext.carousel.Carousel',
alias: 'widget.myCarousel',
config: {
myitems: 0,
},
updateMyItems: function(newItem) {
var localCarouselItems = [];
Ext.each(newItems, function(item){
localCarouselItems.push({
xtype:'localItem',
data:item.data
});
});
this.setItems(localCarouselItems);
this.setActiveItem(0);
}
})
what this does is basically create an array of new items of type localItem from the store when one calls setMyItems and sets the data (to be used with xtemplate or whatever) for each of those items.
If anybody needs more details please ask and I'll update my answer.

insert in sencha touch data store

Could someone please explain how the insert works to add a record in a datastore
with tha fields: "title", "info" and "price"?
because i tried some things and none of them work. and the sencha website doesnt make it very clear.
Adding a new item to an existing Store isn't that hard actually.
First of you will need to configure your model and store. In your question you name the fields 'title, 'info' and 'price'.
Model:
Ext.regModel('myModel', {
fields: [
{name: 'id', type: 'int' },
{name: 'title', type: 'string' },
{name: 'info', type: 'string' },
{name: 'price', type: 'int' }
]
});
Next you configure the store that will hold the data, based on the above model. I think that, in your case, it should be a model without any data preloaded via, for example, JSON?
So lets make a localstorage (empty store). The Store consists of the model (myModel), you give it a storeID (so that you can later on reference the store by this ID). The proxy is localstorage and the unique ID of the Store will be the ID field of the Model.
Store:
var myStore = new Ext.data.Store({
model: "myModel",
storeId: "myStoreID",
proxy: {
type: "localstorage",
id: "id"
}
});
Now, suppose you have some kind of Form (in which the user can add input a title, info and price, and you want to add these items to the existing store on submittal.
Within the handler of the submittal button you now have to 'call' the store, and perform the add function on it. Within this add function you will have to define the params (the model params) and the data to insert.
Below I have used a mixture of fixed data and a variable to insert.
myStoreID.add({ title: "Mijn Titel", info: "Informatie, price: prijsvar });
The store will now be filled will now be filled with an extra data-record which you can use. Lets say for example that the store is attached to a dataview, then you can perform:
dataView.update();
The above isn't a full tutorial, but I think this will help you along?
Just an update of the YDL answer.
As per the dataView should be related to the updated store, the last sentence dataView.update() should not be needed, due to the automatic update of the views related to a store when it change.
new Ext.DataView({
store: MyStore,
itemSelector: 'div.thumb',
tpl: thumbTpl
});
later, if I do the following, the new item should be displayed in views (List, DataView, etc.) that have MyStore as store.
MyStore.add(newItem);
HTH.
Milton Rodríguez.
If you are trying to pass in an object that was returned from a getValue() on your form, make sure that you run a
myStore.sync();
after you have called the add() method, or you wont see it in your browsers local store.
It is Very easy try these
// first get those values and store in locally
var A_select1=Ext.getCmp('select1').getValue(); // get value
localStorage.setItem("Adult1_select1",A_select1); // set localStore
var AdultSalutation={
'Adult1_select1':A_select1, // assign the value
};
var AdultSalutationstore = Ext.getStore('Adult_AdultSalutationstore'); // get store
AdultSalutationstore.add(AdultSalutation); // add object
AdultSalutationstore.sync(); // sync
AdultSalutationstore.load(); // load

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.