I wrote the following implementation of combo box with dynamic data upload.
Code
Loyalty.tools.DictionaryComboBox = Ext.extend(Ext.form.ComboBox,
{
defaultConfig:{
defaults:{
labelWidth:150
},
displayField:'value',
valueField:'key',
forceSelection:true,
mode:'local',
typeAhead: true,
triggerAction: 'all',
selectOnFocus:true
},
constructor:function (config) {
Ext.apply(config, this.defaultConfig);
config['store'] = new Ext.data.Store({
fields:['key', 'value', 'description'],
proxy:{
type:'ajax',
url:config.dictionaryPath + '/' + config.dictionaryName
}
});
Loyalty.tools.DictionaryComboBox.superclass.constructor.call(this, config);
}
}
);
and I use it the following way
new Loyalty.tools.DictionaryComboBox({
fieldLabel: Loyalty.messages['company.grid.filter.forma'],
dictionaryPath: config.dictionaryPath,
dictionaryName: 'forma',
name: 'forma',
id:'forma',
allowBlank:true,
labelWidth:config.labelWidth
}),
I have the two problems
1) How can I get the list data when combo box is loading( rather than on the first click)
2) and if I'm putting a key in the combo box so that it immediately display the desired value?
1) how are you loading the store. I think you need to add autoLoad: true like so
fields:['key', 'value', 'description'],
autoLoad: true,
2) are you asking how do i select the combo box
var mycombo = Ext.getCmp('mycombo');
mycombo.setValue(id);
i decided my problem. Unfortunately I had to use not "right" metod
Loyalty.tools.DictionaryComboBox = Ext.extend(Ext.form.ComboBox,
{
defaultConfig:{
defaults:{
labelWidth:150
},
displayField:'value',
valueField:'key',
forceSelection:true,
queryMode: 'local',
typeAhead: true,
triggerAction: 'all',
selectOnFocus:true
},
constructor:function (config) {
Ext.apply(config, this.defaultConfig);
var isStoreProvided = (config['store'] == undefined);
if (isStoreProvided) {
var el = this;
config['store'] = new Ext.data.Store({
fields:['key', 'value', 'description'],
autoLoad:true,
proxy:{
type:'ajax',
url:config.dictionaryPath + '/' + config.dictionaryName
},
listeners: {
'load': function() {
if (config['initialValue'] != undefined) {
el.setValue(config['initialValue']);
config['initialValue'] = undefined;
}
}
}
});
}
Loyalty.tools.DictionaryComboBox.superclass.constructor.call(this, config);
}
}
);
Related
I am trying to get the number of items in the combo box so that I can make the first value by default visible in the combo box using the getCount() method but I see it always return 0 so cannot get the first item to be displayed in the combo box.
Code for my combo box is as shown below:
Ext.define('something....', {
controller: 'some Controller',
initComponent: function() {
var me,
me = this;
me.items = [{
xtype: 'form',
items: [{
xtype: 'combo',
itemId: 'nameId',
name:'nameId',
labelAlign: 'top',
fieldLabel: 'Name',
store: me._getNames(),
//disabled:some condition?true:false,//doesn't gray out combo
valueField:'dataId',
displayField: 'firstName',
editable: false,
listeners:{
afterrender: function(combo,component) {
var combo = me.down('#nameId');
var nameStore = combo.getStore();
var setFirstRecord = function(combo){
var nameStore = combo.getStore();
if(nameStore.getCount() === 1){
combo.setValue(nameStore.getAt(0));
}
}
if(nameStore.isLoaded() === false){
nameStore.on('load', function(nameStore){
setFirstRecord(combo);
},this,{
single:true
});
}else{
setFirstRecord(nameStore);
}
},
}
}]
}];
}
Code for the store is as below:
_getNames: function (){
var nameStore = Ext.create('Ext.data.Store', {
autoLoad: true,
proxy: {
type: 'ajax',
url: 'name.json',
reader: {
type: 'json',
rootProperty:'items',
transform: function (data) {
var data = {
items: [{
dataId: data[0].dataId,
firstName: data[0].name.firstName,
nameDetails: data[0].nameDetails
}]
}
return data;
}
},
},
fields: ['dataId', 'firstName','nameDetails']
});
return namesStore;
}
})
The result returned from the api to populate the store is as follows:
[
{
"dataId":1,
"name":{
"dataId":1,
"firstName":"Julie",
"code":"10",
"connectionList":[
"EMAIL"
]
},
"nameDetails":{
"EMAIL":{
"dataId":1,
"detail":"EMAIL"
}
}
}
]
Any suggestions on what's missing would be great!
I am written that example for you in Sencha Fiddle: https://fiddle.sencha.com/#view/editor&fiddle/3cdl
That solve your problem:
combo.getStore().on("load",
function (store, records, successful, operation, eOpts) {
if (store.getData().length > 0)
combo.setValue(store.getData().get(0).getData().id)
},
this
)
You must check if store is loaded or not and write appropriate code:
...
...
xtype: 'combo',
itemId: 'nameId',
name: 'nameId',
labelAlign: 'top',
fieldLabel: 'Name',
store: this._getNames(),
valueField: 'dataId',
displayField: 'firstName',
editable: false,
listeners: {
afterrender: function (combo) {
var store = combo.getStore();
var setFirstRecord = function (combo) {
var store = combo.getStore();
if (store.getCount() === 1) {
combo.setValue(store.getAt(0));
}
}
if (store.isLoaded() === false) {
store.on('load', function (store) {
setFirstRecord(combo);
}, this, {
single: true
});
} else {
setFirstRecord(combo);
}
}
}
...
...
I have some store, which is formed data. On panel, it looks how "fieldName" and text field (in depension from invoked form).
For example, on one form is displayed "name document" and field, on another: date of selling and date field. Data is formed dynamically.
Here is store:
tableTempStore = new Ext.data.JsonStore({
url: objectUrlAddress,
baseParams: {
'objectID': objectID
},
root: 'Fields',
fields: [{
name: 'Hint'
}, {
name: 'Type',
type: 'int'
}, {
name: 'Value'
}, {
name: 'Index',
type: 'int'
}, {
name: 'IsRequired',
type: 'bool'
}, {
name: 'Identifier'
}, {
name: 'EnumList'
}, {
name: 'Directory'
}, {
name: 'Data'
}],
listeners: {
load: function (obj, records) {
Ext.each(records, function (rec) {
var item = null;
switch (rec.get('Type')) {
case 0: // целое
item = new Ext.form.NumberField();
item.id = rec.get('Identifier');
item.fieldLabel = rec.get('Hint');
var isRequired = rec.get('IsRequired');
item.anchor = '100%';
item.allowBlank = !isRequired;
item.disabled = editDisabled;
item.value = rec.get('Data');
break;
case 1: // вещественное
item = new Ext.form.NumberField();
item.id = rec.get('Identifier');
item.fieldLabel = rec.get('Hint');
var isRequired = rec.get('IsRequired');
item.anchor = '100%';
item.allowBlank = !isRequired;
item.allowDecimals = true;
item.disabled = editDisabled;
item.value = rec.get('Data');
break;
case 5: // SQL-справочник
var dataValues = Ext.util.JSON.decode(rec.get('EnumList'));
var dataArray = Object.keys(dataValues).map(function (k) {
return [k, dataValues[k]]
});
item = new Ext.form.ComboBox({
typeAhead: true,
width: '100%',
triggerAction: 'all',
forceSelection: true,
editable: false,
hiddenName: rec.get('Identifier'),
mode: 'local',
store: new Ext.data.ArrayStore({
fields: [{
name: 'myId',
type: 'string'
}, {
name: 'displayText'
}],
data: dataArray
}),
valueField: 'myId',
displayField: 'displayText',
disabled: editDisabled
});
item.id = '_' + rec.get('Identifier');
item.anchor = '100%';
item.fieldLabel = rec.get('Hint');
var isRequired = rec.get('IsRequired');
item.allowBlank = !isRequired;
item.value = rec.get('Data');
break;
}
if (item != null) {
templateGrids.add(item);
columnsTable = item.__proto__.constructor.xtype;
var s = null;
else if (rec.get('Type') == 4) {
var dataValues = Ext.util.JSON.decode(rec.get('EnumList'));
var dataArray = Object.keys(dataValues).map(function (k) {
return [k, dataValues[k]]
});
combo = new Ext.grid.GridEditor(new Ext.form.ComboBox({
id: item.id,
allowBlank: item.allowBlank,
typeAhead: true,
lazyRender: true,
triggerAction: 'all',
forceSelection: true,
queryMode: 'local',
editable: false,
value: item.value,
hiddenName: rec.get('Identifier'),
mode: 'local',
store: new Ext.data.ArrayStore({
fields: [{
name: 'myId',
type: 'string'
}, {
name: 'displayText',
type: 'string'
}],
data: dataArray
}),
valueField: "myId",
displayField: "displayText",
disabled: editDisabled
}));
}
source[item.fieldLabel] = '';
grid.customEditors['Сохранить в'] = combo;
grid.getColumnModel().setConfig([{
header: "Поле"
}, {
header: "Значение",
dataIndex: '',
renderer: Ext.util.Format.comboRenderer(combo)
}]);
grid.setSource(source);
};
});
}
}
});
Here's my property grid:
grid = new Ext.grid.PropertyGrid({
url: objectUrlAddress,
id: 'propGrid',
autoFill: true,
autoHeight: true,
width: 200,
store: tableTempStore,
width: 600,
style: 'margin:0 auto;margin-top:10px;'
});
Problem with combo box. It show itemValue instead fieldValue on cell, and I don't know how to resolve this problem. How can I do? Thanks in advance.
For rendering I used function:
Ext.util.Format.comboRenderer = function (combo) {
return function (value) {
var record = combo.findRecord(combo.valueField, value);
return record ? record.get(combo.displayField) : combo.valueNotFoundText;
}
};
But it not worked.
Below is my code to display three comboboxes, which will be Filter by severity, start release and end release. When I refresh the page I want comboboxes to remember what was selected earlier. Now it shows the current release in both the comboboxes.
Any help on this
launch: function() {
var that = this;
this.down('#SevFilter').add({
xtype: 'rallyattributecombobox',
cls: 'filter',
itemId: 'severity',
model: 'Defect',
labelWidth: 117,
fieldLabel : 'Filter By Severity:',
field: 'Severity',
allEntryText: '-- ALL --',
allowNoEntry: true,
_insertNoEntry: function(){
var record;
var doesNotHaveAllEntry = this.store.count() < 1 || this.store.getAt(0).get(this.displayField) !== this.allEntrylText;
if (doesNotHaveAllEntry) {
record = Ext.create(this.store.model);
console.log("record value", record);
record.set(this.displayField, this.allEntryText);
record.set(this.valueField, "-1");
this.store.insert(0, record);
}
/*var doesNotHaveNoEntry = this.store.count() < 2 || this.store.getAt(1).get(this.displayField) !== this.noEntryText;
if (doesNotHaveNoEntry) {
record = Ext.create(this.store.model);
record.set(this.displayField, this.noEntryText);
record.set(this.valueField, null);
this.store.insert(1, record);
}*/
},
listeners: {
//ready: this._onSevComboBoxLoad,
select: this._onSevComboBoxSelect,
scope: this
}
});
var button = this.down('#goButton');
button.on('click', this.goClicked, this);
this.down('#SevFilter').add({
xtype: 'rallyreleasecombobox',
//multiSelect: true,
itemId: 'priorityComboBox',
fieldLabel: 'Release Start:',
model: 'release',
width: 400,
valueField: 'ReleaseStartDate',
displayField: 'Name',
// multiSelect: true,
//field: 'Name',
_removeFunction: function(){
console.log("this.store");
},
listeners: {
//select: this._onSelect,
select: this._onFirstReleaseSelect,
scope: this
}
});
this.down('#SevFilter').add({
xtype: 'rallyreleasecombobox',
itemId: 'priorityComboBox2',
fieldLabel: 'Release End:',
model: 'release',
//multiSelect: true,
stateId: 'rally.technicalservices.trend.defect.release',
stateful: true,
stateEvents: ['change'],
width: 400,
valueField: 'ReleaseDate',
displayField: 'Name',
listeners: {
change: function(box) {
var start_date = this.down('#priorityComboBox2').getDisplayField();
this.logger.log(start_date);
},
ready: this._removeFutureReleases,
select: this._onSecondReleaseSelect,
// ready: this._onLoad,
scope: this
},
});
},
In javascript you may use localstorage.
Here is an app example that retains State and Release selections in respective compboboxes when page is refreshed:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
items: [
{html:'Select a Filter checkbox to filter the grid'},
{
xtype: 'container',
itemId: 'StateFilter'
},
{
xtype: 'container',
itemId: 'ReleaseFilter'
}
],
launch: function() {
document.body.style.cursor='default';
this._createFilterBox('State');
this._createFilterBox('Release');
},
_createFilterBox: function(property){
this.down('#'+property+'Filter').add({
xtype: 'checkbox',
cls: 'filter',
boxLabel: 'Filter table by '+property,
id: property+'Checkbox',
scope: this,
handler: this._setStorage
});
this.down('#'+property+'Filter').add({
xtype: 'rallyattributecombobox',
cls: 'filter',
id: property+'Combobox',
model: 'Defect',
field: property,
value: localStorage.getItem(property+'Filtervalue'), //setting default value
listeners: {
select: this._setStorage,
ready: this._setStorage,
scope: this
}
});
},
_setStorage: function() {
localStorage.setItem('StateFiltervalue',Ext.getCmp('StateCombobox').getValue());
localStorage.setItem('ReleaseFiltervalue',Ext.getCmp('ReleaseCombobox').getValue());
console.log('localStorage State: ', localStorage.StateFiltervalue,', localStorage Release:', localStorage.ReleaseFiltervalue);
this._getFilter();
},
_getFilter: function() {
var filter = Ext.create('Rally.data.wsapi.Filter',{property: 'Requirement', operator: '=', value: 'null'});
filter=this._checkFilterStatus('State',filter);
filter=this._checkFilterStatus('Release',filter);
if (this._myGrid === undefined) {
this._makeGrid(filter);
}
else{
this._myGrid.store.clearFilter(true);
this._myGrid.store.filter(filter);
}
},
_checkFilterStatus: function(property,filter){
if (Ext.getCmp(property+'Checkbox').getValue()) {
var filterString=Ext.getCmp(property+'Combobox').getValue()+'';
var filterArr=filterString.split(',');
var propertyFilter=Ext.create('Rally.data.wsapi.Filter',{property: property, operator: '=', value: filterArr[0]});
var i=1;
while (i < filterArr.length){
propertyFilter=propertyFilter.or({
property: property,
operator: '=',
value: filterArr[i]
});
i++;
}
filter=filter.and(propertyFilter);
}
return filter;
},
_makeGrid:function(filter){
this._myGrid = Ext.create('Rally.ui.grid.Grid', {
itemId:'defects-grid',
columnCfgs: [
'FormattedID',
'Name',
'State',
'Release'
],
context: this.getContext(),
storeConfig: {
model: 'defect',
context: this.context.getDataContext(),
filters: filter
}
});
this.add(this._myGrid);
}
});
The source is available here.
You could use Sencha localstorage proxy. This way you can keep consistency in your project and use a localstorage based store across all your code.
You can use stateful and stateId configurations to enable last selection. Here is an example of my code. Here what I am doing is to create a custom combobox that will show two options: Platform and program. Then for stateId, you can use any string that you want:
_createCategoryFilter: function()
{
// The data store containing the list of states
var platformTypeList = Ext.create('Ext.data.Store',
{
fields: ['abbr', 'name'],
data : [
{"abbr":"PLAN", "name":"Platform"},
{"abbr":"CURR", "name":"Program"},
//...
]
});
// Create the combo box, attached to the states data store
var platformTypeFilter = Ext.create('Ext.form.ComboBox',
{
fieldLabel: 'Select category',
store: platformTypeList,
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
stateful: true,
stateId: 'categoryFilter',
listeners:
{
afterrender: function(param)
{
console.log('afterrender - category param is', param.rawValue);
CategoryFilterValue = param.rawValue;
LoadInformation();
},
select: function(param)
{
console.log('select - category param is', param.rawValue);
CategoryFilterValue = param.rawValue;
},
scope: this,
}
});
this.add(platformTypeFilter);
},
I'm trying to convert this reader from Ext 3 to Ext 4. JavaScript is throwing an exception. Did I convert this correctly?
JavaScript exception:
Uncaught TypeError: Cannot read property 'prototype' of undefined
Code (converted lines commented):
Ext.onReady(function () {
Ext.Direct.addProvider(Ext.app.REMOTING_API);
//var reader = new Ext.data.JsonReader({ // convert from ext 3 to ext 4
var reader = Ext.create('Ext.data.JsonReader', {
totalProperty: 'results',
successProperty: 'success',
idProperty: 'id',
root: 'data'
}, [{
name: 'id'
}, {
name: 'email',
allowBlank: false
}, {
name: 'first',
allowBlank: false
}, {
name: 'last',
allowBlank: false
}]
);
//var writer = new Ext.data.JsonWriter({ // convert from ext 3 to ext 4
var writer = Ext.create('Ext.data.JsonWriter', {
returnJson: false,
writeAllFields: true
});
//var store = new Ext.data.DirectStore({ // convert from ext 3 to ext 4
var store = Ext.create('Ext.data.DirectStore', {
api: {
read: CRUDSampleMethods2.read,
create: CRUDSampleMethods2.create,
update: CRUDSampleMethods2.update,
destroy: CRUDSampleMethods2.destroy
},
reader: reader,
baseParams: {
dummy: 'blubb'
},
writer: writer,
paramsAsHash: true,
batchSave: false,
batch: false,
prettyUrls: false,
remoteSort: true,
listeners: {
load: function (result) { },
loadexception: function () {
},
scope: this
}
});
// ... code continues
EDIT:
Fixed this:
var reader = Ext.create('Ext.data.JsonReader', {
totalProperty: 'results',
successProperty: 'success',
idProperty: 'id',
root: 'data'
});
And added model:
var store = Ext.create('Ext.data.DirectStore', {
model: 'User',
api: {
JsonReader's constructor accept only one param. So your code doesn't really define the field list. Yet the field list is mandatory, either in the store (if the store doesn't use a model), or the model. And that's the type of error you get when a store is missing fields declaration...
I have an ExtJs Combobox with multiple true and I want to show "X values selected" on the input field instead of "Value 1, Value 2, Value 3". I tried with select listener but when I set the value to the input field and then you call multicombo.getValue() it takes the value from the input field. I would need something like take the value from the valueField (a hidden input).
My code:
var multiCombo = Ext.create('Ext.form.field.ComboBox', {
renderTo: item.id,
multiSelect: true,
displayField: 'name',
editable: false,
valueField: 'id',
emptyText: 'Select',
hiddenName: 'data[Model][' + item.getAttribute('question-id') + '][value]',
submitValue: true,
inputType: 'hidden',
value: selectedOptions,
width: 300,
store: store,
queryMode: 'local',
listeners: {
expand: function (combo) {
var values = Ext.get(combo.hiddenDataEl.dom.lastChild).dom.value;
values = values.split(",");
Ext.each(values, function (value, i) {
values[i] = parseInt(value);
});
combo.setValue(values);
Ext.get(combo.getInputId()).dom.value = values.length + ' selected';
},
select: function (combo, values) {
if (values[values.length - 1].data.id === parseInt(item.getAttribute('not-applicable'))) {
combo.setValue(parseInt(item.getAttribute('not-applicable')));
} else {
var notApplicable = -1;
var newValues = combo.getValue();
if ((notApplicable = combo.getValue().indexOf(parseInt(item.getAttribute('not-applicable')))) != -1) {
newValues.splice(notApplicable, 1);
}
combo.setValue(newValues);
}
Ext.get(combo.hiddenDataEl.dom.lastChild).dom.value = combo.getValue().join(',');
optionsSelected = combo.getValue();
Ext.get(combo.getInputId()).dom.value = optionsSelected.length + ' selected';
},
change: function (combo) {
if (item.getAttribute('required') == 'true') {
if (combo.getValue().length == 0) {
question.findParentNode('li', 1, true).addCls("is_required");
} else {
question.findParentNode('li', 1, true).removeCls("is_required");
}
//There is no ExtJs equivalent for this
$('#' + combo.getInputId()).keyup();
}
}
}
});
I'm not sure that I follow what is going on with all of the event handlers (so I may be missing something), but the simplest way to achieve what you described in your first sentence above is to provide your own implementation for the combo's getDisplayValue method. Here it is in the docs.
Just set it up to return a count of how many values are selected. Here's an example:
var multiCombo = Ext.create('Ext.form.field.ComboBox', {
renderTo: item.id,
multiSelect: true,
displayField: 'name',
// your own getDisplayValue implementation
getDisplayValue: function() {
return multiCombo.value.length + ' values selected';
},
editable: false,
valueField: 'id',
emptyText: 'Select',
hiddenName: 'data[Model][' + item.getAttribute('question-id') + '][value]',
submitValue: true,
inputType: 'hidden',
value: selectedOptions,
width: 300,
store: store,
queryMode: 'local',
});
Also this may help:
getDisplayValue: function() {
return (this.displayTplData.length > 1) ? this.displayTplData.length + ' selected' : this.displayTplData[0].name;
},