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;
},
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 dynamicly
Here is store:
tableTempStore = new Ext.data.JsonStore({
url: objectUrlAddress,
baseParams: {
'objectID': objectID
},
root: 'Fields',
fields: [{
name: 'Type',
type: 'int'
}, {
name: 'Value'
}, {
name: 'IsRequired',
type: 'bool'
}, {
name: 'Identifier'
}, {
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;
}
if (item != null) {
templateGrids.add(item);
columnsTable = item.__proto__.constructor.xtype;
source[item.fieldLabel] = '';
var s = null;
if (columnsTable == 'textfield')
{
s = 'textfield';
colm = {
xtype: s,
id: item.id,
allowBlank: item.allowBlank,
format: item.format,
value: item.value,
editable: true,
emptyText: item.emptyText,
disabled: item.disabled
};
}
else if (columnsTable == 'combo')
{
s = 'combo';
colm = {
xtype: s,
id: item.id,
allowBlank: item.allowBlank,
format: item.format,
value: item.value,
editable: true,
emptyText: item.emptyText,
disabled: item.disabled
};
}
else if (columnsTable == 'datefield')
{
s = 'datefield';
colm = {
xtype: s,
id: item.id,
allowBlank: item.allowBlank,
format: item.format,
value: item.value,
editable: true,
emptyText: item.emptyText,
disabled: item.disabled
};
}
});
for (var i = 0; i < templateGrids.getStore().data.length; i++) {
templateGrids.getColumnModel().setConfig([
{header: 'Name', id:'name', width:200},
{header:'Value', id:'val', dataIndex: rec.get('Value'), editable:true, width:200, editor: colm}]);
};
}
}
});
This code had worked in a form, but I need to use Grid (or Editor Grid). I know, how displayed field name ("document name" and etc.), but I don't understand, how displayed text field or etc. I try use loop, but on second column in xtype displayed last type in store. How i can resolve this problem?!
Here is a grid:
var templateGrids = new Ext.grid.EditorGridPanel({
id: 'tableId',
height:300,
width: '100%',
clicksToEdit:1,
frame: true,
store: tableTempStore,
columns: [
{header: 'Name'},
{header: 'Value'}]
});
I have this callback function, which creates list of categories on my page.
this.getCategoryAdCount(function (categories) {
//added selectize plugin to display multiply choice
var values = categories.map(function (cat) {return { item : cat.id, text : cat.name + ' (' +cat.count + ')'}; }); //this is my data from the server
this.$filtercat.selectize({
plugins: ['remove_button'],
delimiter: ',',
persist: false,
maxItems: 5,
options: values,
labelField: "text",
valueField: "item",
sortField: 'text',
searchField: 'text',
create: function(input) {
return {
value: input,
text: input
}
}
});
}.bind(this));
It works good, but I have already existing function, which calls .selectize on every $('select') element on my page
$('select').each(function(k, v) {
var el = $(v);
var options = SJA.Config.selectizeOptions;
el.selectize(options);
});
In this config I have list of options
selectizeOptions: {
persist: true,
maxOptions: 99999,
dropdownParent: 'body',
sortField: false,
render: {
option: function(data) {
return '<div data-value="' + data.value + '" title="' + data.text + '" data-selectable class="option">' + data.text + '</div>';
}
}
},
So I don't want to call .selectize once again inside my callback function. Is it possible to extend somehow options only for the this.$filtercat variable without calling .selectize ?
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 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);
}
}
);