Dojo Select onchange not firing on creating Select box programmatically - dojo

I have two dojo select dropdowns. First dropdown is populated on page load and on selecting a value from first drop down, second select box should be populated.
I create the second select box programatically and i destroy it for every on change event of the first dropdown box.( this is to avoid widget already registered error).
But when i select any of the option from second drop down select, it does not fire onchange event.
Pls help on this.
My code is
require(["dojo/parser","dijit/form/RadioButton","dojo/ready","dojo/data/ItemFileReadStore","dijit/registry","dijit/form/Select","dojo/ready","dojo/dom-form", "dojo/dom", "dojo/on", "dojo/request","dojo/domReady"],
function(parser,RadioButton,ready,ItemFileReadStore,registry,Select,ready,Form,dom,on,request){
parser.parse();
var manuData;
var modelData;
var shaftType;
var modelId;
var clubMfr;
var clubType;
var manufacturerList;
dojo.connect(dijit.byId("clubtype"),"onChange",function(event){
clubType=registry.byId("clubtype").get('value');
console.log(clubType);
var id= registry.byId("clubtype");
var option1= registry.byId("manufacturer");
request("/tradeIn/"+clubType).then(function(list){
manuData=list;
var data1 = dojo.fromJson(manuData);
var readstore=new ItemFileReadStore({ data:{
identifier : "manufacturer",
label: "manufacturer",
items : data1,
}});
if(typeof registry.byId("manufacturerId") != "undefined"){
registry.byId("manufacturerId").destroyRecursive();
}
manufacturerList=new Select({
name:"manufacturerId",
id:"manufacturerId",
store:readstore,
onSetStore: function() {
this.options.unshift({selected:'true',label:'Choose One', value:'NULL'});
this._loadChildren();
}
}).placeAt("manuList");
manufacturerList.startup();
});
}
);
dojo.connect(
dijit.byId("manufacturerId"),"onChange",function(event){
var manufacturerId=registry.byId("manufacturerId").get('value');
clubMfr=manufacturerId;
var model= registry.byId("model");
model.removeOption(dijit.byId("model").getOptions());
request("/tradeIn/"+manufacturerId+"/"+clubType).then(function(list){
modelData=list;
var data1 = dojo.fromJson(modelData);
var readstore=new ItemFileReadStore({ data:{
identifier : "model",
label: "model",
items : data1
}});
if(typeof registry.byId("modelId") != "undefined"){
registry.byId("modelId").destroyRecursive();
}
var modelList=new Select({
name:"modelId",
id:"modelId",
store:readstore,
onSetStore: function() {
this.options.unshift({selected:'true',label:'Choose One', value:'NULL'});
this._loadChildren();
}
}).placeAt("modelList");
modelList.startup();
});
}
);
dojo.connect(
dijit.byId("model"),"onChange",function(event){
modelId=registry.byId("model").get('value');
console.log("model "+modelId);
}
);
});

You need to disconnect the onChange event before destroying the select and to reconnect it after creating the select. To achieve the disconnection, you can use own() method.
Here is how it should look like:
if(typeof registry.byId("manufacturerId") != "undefined"){
registry.byId("manufacturerId").destroyRecursive();
}
manufacturerList=new Select({/* ... */});
manufacturerList.own(dojo.connect(
dijit.byId("manufacturerId"),"onChange",function(event){ /* ... */ }
));
Note: This is extremely dirty. The proper approach would be to NOT destroy the second select and instead to update its data.
See the snippets for updating it:
require(['dijit/form/Select', 'dojo/data/ItemFileReadStore', 'dojo/domReady!'], function(Select, ItemFileReadStore) {
var initialStoreData = [
{value: "AL", label: "Alabama"},
{value: "AK", label: "Alaska"},
{value: "AZ", label: "Arizona"}
];
var changedStoreData = [
{value: "CA", label: "California"},
{value: "CO", label: "Colorado"},
{value: "CT", label: "Connecticut"}
];
var prepareData = function(storeData) {
//because the store return sorted data, I have added a space before the word 'Choose'. So it comes first
return [{value: '', label: ' Choose one'}].concat(storeData);
}
var readStore=new ItemFileReadStore({
data:{
identifier: "value",
label: "label",
items: prepareData(initialStoreData)
}
});
var selectWidget = new Select({
store: readStore
});
selectWidget.placeAt(document.getElementById('test'));
selectWidget.startup();
btn.onclick = function() {
var newReadStore=new ItemFileReadStore({
data:{
identifier: "value",
label: "label",
items: prepareData(changedStoreData)
}
});
selectWidget.set('store', newReadStore);
}
});
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/resources/dojo.css">
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dijit/themes/tundra/tundra.css">
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojox/form/resources/CheckedMultiSelect.css">
<div id="test" class="tundra">
<button id="btn">change data in select</button>
</div>

Related

dojox.grid.DataGrid sort order bug on mixed case strings?

I know Dojo is getting quite old now but we still have apps that are using it.
One thing that was pointed out was the sort facility on the dojox.grid.DataGrid table of users. Our users table has grown over time so it's useful to order by the name column. However, we find that, while most names were entered with a Capital first letter, some names were entered all in lowercase and when I click on the name column header for sorting, I find that the Capitalised names appear in alphabetical order BUT followed by lowercase name in the same order at the bottom.
e.g. The raw data:
Tom
Dick
harry
After "sorting" displays as :
Dick
Tom
harry
Code example, using Dojo 1.8.3, as follows:
require(["dojox/grid/EnhancedGrid",
"dojo/data/ItemFileWriteStore",
"dojo/parser",
"dojo/on",
'dojo/domReady!'
],
function(EnhancedGrid, ItemFileWriteStore, Filter, parser, on) {
var data = {
items: [
{ name: 'Tom', age: 29 },
{ name: 'Dick', age: 9 },
{ name: 'harry', age: 19 }
]
};
var gridStore = new ItemFileWriteStore({
data: data
});
var gridStructure = [
[
{ 'name': 'Name', 'field': 'name' },
{ 'name': 'Age' , 'field': 'age' }
]
];
var mygrid = new EnhancedGrid({
id: "grid",
store: gridStore,
structure: gridStructure,
autoHeight: true,
autoWidth: true
}, "mydatagrid");
mygrid.startup();
}
);
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/grid/enhanced/resources/claro/EnhancedGrid.css" rel="stylesheet" />
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/claro/claro.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script>
<div id="container" class="claro">
<div id="mydatagrid"></div>
</div>
How do I sort a column of mixed case names correctly?
i.e. to display sorted grid as:
Dick
harry
Tom
Thanks
I managed to get a solution through a suggestion on a related DataGrid post: dojox.grid.DataGrid custom sort method?
Basically, you can use the "comparatorMap" of the ItemFileWriteStore (or ItemFileReadStore)
require(["dojox/grid/EnhancedGrid",
"dojo/data/ItemFileWriteStore",
"dojo/parser",
"dojo/on",
'dojo/domReady!'
],
function(EnhancedGrid, ItemFileWriteStore, Filter, parser, on) {
var data = {
items: [
{ name: 'Tom', age: 29 },
{ name: 'Dick', age: 9 },
{ name: 'harry', age: 19 }
]
};
var gridStore = new ItemFileWriteStore({
data: data
});
var gridStructure = [
[
{ 'name': 'Name', 'field': 'name' },
{ 'name': 'Age' , 'field': 'age' }
]
];
//====================================================================================
//= Define the comparator function for "Name" ========================================
//====================================================================================
gridStore.comparatorMap = {};
gridStore.comparatorMap["name"] = function(a,b) {
var nameA = a.toLowerCase().trim(), nameB = b.toLowerCase().trim();
if (nameA < nameB) //sort string ascending
return -1;
if (nameA > nameB)
return 1;
return 0; //default return value (no sorting)
}
//====================================================================================
//====================================================================================
//====================================================================================
var mygrid = new EnhancedGrid({
id: "grid",
store: gridStore,
structure: gridStructure,
autoHeight: true,
autoWidth: true
}, "mydatagrid");
mygrid.startup();
}
);
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/grid/enhanced/resources/claro/EnhancedGrid.css" rel="stylesheet" />
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/claro/claro.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script>
<div id="container" class="claro">
<div id="mydatagrid"></div>
</div>

Field keeps old value after update

I have a form which is saved using ajax after each change in one of the fields.
The response from the ajax request is used to update some data in that instance but does not update the data that is used in my form.
The problem is when i change one of the fields, switch fast to the next field and start typing, it changes back to the value that it had before the ajax call after the request is done.
Code sample:
var vueCheckout = new Vue({
el: document.getElementById('vue-container'),
data: {
billing_address: {
'postcode' : '',
'city' : ''
},
shipping_address: {
'postcode' : '',
'city' : ''
}
},
mounted: function () {
this.billing_address = {postcode: 'postcode', city: 'city'};
this.shipping_address = {postcode: '2', city: '2'};
},
methods: {
changeAddress: function(type, key, event) {
this[type][key] = event.target.value;
var $this = this;
setTimeout(function(){
$this.shipping_address = {postcode: '3', city: '3'};
}, 1000);
},
}
});
<div id="vue-container">
<div>
<input type="text" name="billing[postcode]" :value="billing_address.postcode" #change="changeAddress('billing_address','postcode',$event)" maxlength="5">
<input type="text" name="billing[city]" :value="billing_address.city" #change="changeAddress('billing_address','city',$event)">
</div>
<div>
<span>{{ shipping_address.postcode }}</span> - <span>{{ shipping_address.city }}</span>
</div>
</div>
How to reproduce:
https://jsfiddle.net/3au4m5qw/1/
Try changing the value of postcode and then switch fast to the next field (city) and change the value to something else.
You will see that the value is back to the original.
EDIT: jsfiddle with v-model.lazy: https://jsfiddle.net/hym63pL7/
Use
v-model="billing_address.city"
instead of :value. V-model is two way binding and fixes your issue.
I think even changing to v-model the data from the ajax request won't be displayed because the data values will change but they won't be rendered. You need to wait until the DOM is updated using nextTick.
https://v2.vuejs.org/v2/api/#Vue-nextTick
var vueCheckout = new Vue({
el: document.getElementById('vue-container'),
data: {
billing_address: {
'postcode' : '',
'city' : ''
},
shipping_address: {
'postcode' : '',
'city' : ''
}
},
mounted: function () {
this.billing_address = {postcode: 'postcode', city: 'city'};
this.shipping_address = {postcode: '2', city: '2'};
},
methods: {
changeAddress: function(type, key, event) {
this[type][key] = event.target.value;
var $this = this;
setTimeout(function(){
$this.$nextTick(function() {
$this.shipping_address = {postcode: '3', city: '3'};
})
}, 1000);
},
}
});
Similar issue here:
https://laracasts.com/discuss/channels/vue/vuejs-20-data-gotten-from-backend-via-ajax-can-not-be-shown-in-view

add unit to numberspinner in dojo

I'm creating programmatically a table container with numberspinners in dojo.
Is there a way to add a unit (seconds, meters, etc.) to the spinner?
Or if that's not possible, how can I add a second row with just labels in it? So I can define the units there.
Consider creating a custom widget, which will container your "label" value, here an example.
Note:
You can change the HTML template templateString from label to div if your prefer.
Below I am using ContentPage() but you can a layout component as you which.
require(['dijit/form/NumberSpinner', 'dijit/layout/ContentPane', 'dijit/_WidgetBase', 'dijit/_TemplatedMixin', 'dojo/_base/declare', 'dojo/domReady!'], function(NumberSpinner, ContentPane, _WidgetBase, _TemplatedMixin, declare, domReady) {
var data = {
meters: '1'
},
layout = new ContentPane(),
LabelTextbox = declare([_WidgetBase, _TemplatedMixin], {
label: '',
textboxId: '',
name: '',
value: '',
templateString: '<div><label>${label}</label><div data-dojo-attach-point="textboxNode"></div></div>',
postCreate: function() {
this.inherited(arguments);
this.own(new NumberSpinner({
id: this.textboxId,
name: this.meters,
value: this.value
}, this.textboxNode));
}
});
Object.keys(data).forEach(function (prop, index) {
layout.addChild(new LabelTextbox({
textboxId: prop + '-'+ index,
name: prop,
value: data[prop],
label: 'meters: '
}));
}.bind(this));
layout.placeAt('layout');
layout.startup();
});
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dijit/themes/claro/claro.css" media="screen">
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
<div id="layout"></div>

Add PercentDoneByStoryPoint to HTML DIV

In the 1.x version of the Rally SDK I was able to query and assign to an HTML DIV with a query like the following:
var querySI48 = {
type : 'portfolioitem',
query:'(Name = "Q3 2015 Release (2.8.0)")',
key : 'SI48Key',
fetch: 'PercentDoneByStoryCount'
};
And assign it to a DIV like this:
var WS215 = document.getElementById("WS215");
WS215.innerHTML = "<h2>" + pisInfo + "%</h2>";
How can I assign the PercentDoneByStoryPoint to a DIV with the 2.X SDK? I'm creating a dashboard in Confluence that contains Rally data.
Something similar to the following should do the trick:
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script type="text/javascript" src="/apps/2.0/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function() {
Ext.define('Rally.example.App', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
var me = this;
var divTemplateString = "<h2>{0}: Percent Done by Story Count = {1}</h2>";
Ext.create('Rally.data.wsapi.Store', {
model: 'PortfolioItem/Feature',
fetch: true,
autoLoad: true,
filters: [
{
property: 'FormattedID',
value: 'F15'
}
],
listeners: {
load: function(store, data, success) {
var formattedID = data[0].get('FormattedID');
var pctDoneByStoryCount = data[0].get('PercentDoneByStoryCount');
var divHTML = Ext.String.format(divTemplateString, formattedID, pctDoneByStoryCount);
var div = Ext.get('F15');
me.add({
xtype: 'container',
html: divHTML,
renderTo: div
});
}
},
});
}
});
Rally.launchApp('Rally.example.App', {
name: 'Example'
});
});
</script>
<style type="text/css">
</style>
</head>
<body>
<div id="F15"</div>
</body>
</html>

Give input to a Sencha 2 template

How can I pass arguments to a Sencha 2 template? Below is my small template, have tried different things like defining "field variables" on the template and using the config, and so fourth, but Im definitly doing something wrong. Lets say I want to give arguments "title" and "usageTime", how can I do it
Ext.define('Sencha.templates.AppDetailsUsageTemplate' ,{
extend: 'Ext.XTemplate',
constructor: function (config) {
var html = [
'<div id="{id}" class="limitsList {cls}">',
' <div class="reportsSummaryLeft"> {title} </div>',
' <div class="reportsSummaryRight"> {usageTime} </div>',
' <div style="clear:both"></div>',
'</div>'];
this.callParent(html);
}
});
In my view I wanna do something ala this (pseudo code below):
xtype: 'container',
tpl: Ext.create('Sencha.templates.AppDetailsUsageTemplate',{
title: 'test tittle',
usageTime: 100384
})
I figured it out, give parameters through data:
Examples:
{
id: 'appDetailsMonth',
xtype: 'component',
tpl: Ext.create('Sencha.templates.AppDetailsUsageTemplate')
},{
id: 'appDetailsLifeDuration',
xtype: 'component',
tpl: Ext.create('Sencha.templates.AppDetailsUsageTemplate')
}
And then in applyItems
applyItems:function(newItems, oldItems) {
var i = 0,
iNum = newItems.length,
data = this.getData();
var yesterdayItem = newItems[2];
yesterdayItem.data = {
title: 'Yesterday',
usage: data.dayDuration
};
....
}