Using dijit.InlineEditBox with dijit.form.Select - dojo

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.

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);
}
});
}
});

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.

FileUploadField 'stuck' after submitting form with ExtJS4/DWR

im using extjs4 with dwr3 to upload a file
this is all i have in my form
{xtype: 'fileuploadfield',
name: 'file',
fieldLabel: 'Archivo',
allowBlank: false,
buttonText: 'Seleccionar...'
}, {
xtype: 'button',
text: 'Cargar',
action: 'cargarArchivo'
}
when i click the button (labeled Cargar) it submits the file and stays in the same page, so far so good. Problem is, when i choose another file, the text in the field stays the same instead of showing the new file chosen
this is what i have in my controller:
init: function() {
this.control({
'NciImport button[action=cargarArchivo]': {
click: this.cargaArchivo
}
});
},
cargaArchivo : function (button){
clickedButton = button;
bsNciNiv.cargaArchivoNci(dwr.util.getValue('file'), function(x,y,z){
clickedButton.up('form').down('fileuploadfield').createFileInput(); // funny solution
});
}
The bsNciNiv.cargaArchivoNci part is my DWR service
the line i commented as funny solution kind of works, after adding it the rest works as expected, but i really dont think it is the right solution, just added it as a hint in case its useful
can anyone confirm if this is a bug or if theres a way to fix this? thanks
(btw not sure if this has anything to do with dwr3, but i tagged it anyway)
I just ran into this same problem using Ext-JS 4.1.1 and DWR3. I debugged the DWR javascript and found the cause. When the dwr method parameters include a fileupload field, dwr constructs a multipart post message and a hidden iframe rather than using XmlHttpRequest. As part of this process, it replaces the original fileupload element (this itself is a hidden element, created and managed by the Ext FileUpload component) with a clone (same ID and properties). As a result, the Ext field's fileInputEl property is no longer referring to the replaced element and the component's onFileChange() event handler is not registered for the new element's 'change' event. So, it isn't a bug in Ext-JS.
I worked around it in my callback like this:
var fileInputId = uploadField.fileInputEl.dom.id;
MyDwrService.fileUpload(uploadField.fileInputEl.dom, arg2, function(results) {
uploadField.fileInputEl = Ext.get(document.getElementById(fileInputId));
uploadField.fileInputEl.on({
scope: uploadField,
change: uploadField.onFileChange
});
});
It worked for me in Firefox, Chrome and IE8
My guess is that this component was not designed to upload multiple files (in series).
The issue you are seeing is probably due to this hidden element not getting cleared: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.form.field.File-property-fileInputEl
You can probably file this as a bug with Sencha although they might consider it a feature :)

Dojo: create programatically a menu in an enhancedgrid

I'm trying to create programatically an EnahncedGrid with a menu. I've got the grid to work, but I've been unable to use the menu. It just not shows up. The code is as follows:
<script>
sMenu = new dijit.Menu({});
sMenu.addChild(new dijit.MenuItem({
label: "Delete Record",
iconClass: "dijitEditorIcon dijitEditorIconCancel",
onClick : function(){
alert(1);
}
}));
sMenu.startup();
/**
* El grid propiamente dicho
*/
var grid = new dojox.grid.EnhancedGrid({
id: "grid_"+i,
query: {
idDocument: '*'
},
plugins: {
nestedSorting: true,
indirectSelection: true,
menus: {rowMenu:sMenu}
},
onRowDblClick: openFile,
structure: layout
})
</script>
Any idea what I'm doing wrong?
I haven't used this myself, but I have two possible suggestions:
First, make sure you're dojo.require-ing "dojox.grid.enhanced.plugins.Menu" and are only instantiating the widgets within a dojo.addOnLoad or dojo.ready.
If you've already done that, the second thing I'd suggest is giving your menu an id, and passing that id to the rowMenu property of the menus object (in other words, pass a string, not the widget itself). Although, the way you're doing it seems like it should work, judging from the code.
You can see a test page with working menus here: http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/grid/tests/enhanced/test_enhanced_grid_menus.html