This is a 2-part question:
Primary Question: Say I have a combobox (code below) that is pulling from a store. Say I have an array that I want to filter the data by so that only certain values actually show up in the dropdown. I can't seem to find the parameter that will do that... Is there a simple way to do this?
Secondary question: I also need to be able to disable and reenable items within the drop down based on actions of the user after the dropdown is created. Is there a function that causes items to be reenabled/disabled within the dropdown?
Note: By disabled I mean 'not present' aka removed in the dom, but still present in the non-filtered store.
{
xtype: 'combobox',
anchor: '100%',
name: 'Permission_id',
fieldLabel: 'Permissions',
hideLabel: false,
displayField: 'Name',
forceSelection: true,
store: 'PermissionStore',
typeAhead: true,
valueField: 'id',
valueNotFoundText: 'Add Permission'
}
I think all you need is work with filters. If you want to display only certain values in the dropdown, the only thing you have to do is filter the store and if what yo have is an array, you can use an ArrayStore for that.
About your second question, if you filter your store, original values are not lost, they are save internally as an snapshot then when you clear your filters, old values are displayed again in the dropdonlist.
Please take a look at this working example: http://jsfiddle.net/lontivero/Mz6S4/1/
First answer: the method is .filter(). For example:
var store = Ext.create('Ext.data.ArrayStore', {
fields: ['Id', 'Name'],
data: [
[ 1, 'Lucas' ],
[ 2, 'Pablo' ],
[ 3, 'Francisco' ]
]
});
Ext.create('Ext.form.field.ComboBox', {
fieldLabel: 'Permissions',
displayField: 'Name',
store: store,
valueField: 'Id',
renderTo: Ext.getBody()
});
//Hide Pablo in the dropdownlist
store.filter([
{filterFn: function(record) { return record.get('Name') !== 'Pablo'; }}
]);
// uncomment this to reenable hidden records (to display Pablo again)
//store.clearFilter();
Second answer: clear the store's filters
As lontivero said, filters solve your issue:
primary: array can contain data but filter will hide it from the dropdown
secondary: filters can be changed to hide and show in the dropdown
Your remaining problem, then, is how to change the filter from non-Ext code. Here you can use the fact that Ext is just javascript and can be called from any other javascript that has nothing to do with Ext.
So:
Add some functions that apply the filters to add and remove, in a place/scope that is accessible to the HTML DOM
Add them to the onclick handlers of the (plain HTML) buttons
The trick is really to access the store by using the Ext lookup by id.
So if the following code (extending on lontivero's jsfiddle) is directly in a js file (or in a script tag), it does what you're asking for:
(jsfiddle: http://jsfiddle.net/mCv6A/)
// functions that do the filtering
var noPablo = function(record) { return record.get('Name') !== 'Pablo' }
var noJames = function(record) { return record.get('Name') !== 'James' }
// the combination of functions we'll use
var withoutJamesFilter = [{ filterFn: noPablo }, { filterFn: noJames }]
var withJamesFilter = [{ filterFn: noPablo }]
function addJames()
{
var store = Ext.getStore('people')
store.clearFilter()
store.filter(withJamesFilter)
}
function delJames()
{
var store = Ext.getStore('people')
store.clearFilter()
store.filter(withoutJamesFilter)
}
Ext.onReady(function()
{
var store = Ext.create('Ext.data.ArrayStore', {
id: 'people',
fields: ['Id', 'Name'],
data: [
[ 1, 'Lucas' ],
[ 2, 'Pablo' ],
[ 3, 'Francisco' ],
[ 4 , 'James' ]
]
})
Ext.create('Ext.form.field.ComboBox', {
fieldLabel: 'Permissions',
displayField: 'Name',
store: store,
valueField: 'Id',
renderTo: Ext.getBody()
})
// start without james in list
store.filter(withoutJamesFilter)
})
Things to consider when using it for real (rather than in a simplified example):
wrapping addJames, delJames and the variables (noPablo, noJames etc) they use in an object or immediate function so the variables don't clutter the global (window) scope
rewriting the filter variables to better share implementation (something like a function that takes a list of names and generates a filter array or filter function that filters out those names would be sensible)
Related
I'm trying to edit an open source program (and learn Extjs meanwhile) and I encountered a problem about models. I don't want to put code here since it is too long but I can provide if necessary.
So I got a a class which extends Ext.form.Panel and model "PartModel" assigned to it. This model has a string field called "partNumber" along with many other fields.
In this panel I want to choose a part number from a combobox from predefined values at database and assign it to "partNumber".
The problem is I want to assign value that is "displayed" in the combobox.(Not one of store fields, I'm using a custom XTemplate for it)
How can I do it?
Edit: Adding combobox code. I thought adding "dataIndex: 'partNumber'" would be sufficient to do job but this code isn't working at all. I can see Part Numbers strings from combobox but when I choose one and hit save button it doesn't save. (There are many other fields working well with that save button maybe I just need to add another button to save part number?)
{
xtype: 'combobox',
dataIndex: 'partNumber',
fieldLabel: "Part Number",
labelWidth: 150,
flex: 1,
store:{
xtype: 'store',
autoLoad: true,
model: 'PartGroupsClasses',
proxy: getPartGC()},
queryMode: 'local',
renderTo:Ext.getBody(),
tpl:Ext.create('Ext.XTemplate','<tpl for="."><div class="x-boundlist-item">{code}-{descr}-{ccode}-{cdescr}</div></tpl>'),
displayTpl:Ext.create('Ext.XTemplate','<tpl for=".">{code}{descr}{ccode}{cdescr}</tpl>')
}
Edit2: Figured out save button is basically calling following function.
Ext.override(Ext.data.Model, {
setDataWithAssociations: function(data) {
for (var i in data) {
if (this.fields.containsKey(i)) {
this.set(i, data[i]);
}
if (this.associations.containsKey(i)) {
var store = this[i]();
store.add(data[i]);
}
}
}
});
I would do something like this... in your combobox's model, add an extra field that makes use of the convert function to create your displayValue, and then in your combobox, just use that value for your displayValue property.
Model
Ext.define('MyComboModel', {
extend: 'Ext.data.Model',
fields: [
{
name: 'code',
type: 'string'
},
{
name: 'desc',
type: 'string'
},
{
name: 'ccode',
type: 'string'
},
{
name: 'cdesc',
type: 'string'
},
{
name: 'displayValue',
type: 'string',
convert: function(value, record) {
return record.get('code') +
record.get('desc') +
record.get('ccode') +
record.get('cdesc');
}
}
]
});
Combo
xtype: 'combobox',
name: 'Field2',
valueField: 'displayValue',
displayField: 'displayValue',
fieldLabel: 'Field2',
queryMode: 'local',
Full example.
I dont thing your question is clear enough for a clear answer...
I am unclear on your objective but if you want to have something display on store and behind it have the value on the file please take a look see if this examples helps
Store
this.data = Ext.create('Ext.data.JsonStore', {fields: ['id', 'data'],
data: [{id: 1, data: 'data1'},
{id: 2, data: 'data2'},
{id: 3, data: 'data3'},
{id: 4, data: 'data4'}]});
Combo
xtype:'Combobox',
name:'wtv',
displayField: 'data',
valueField: 'id'
It will display the combo with data but if you get the combo with the selection path and do for example
Selector
refs: [{
ref:Combo
selector:'Panel Combobox[name=wtv]'
}]
Later you can do something like
Panel.getCombo().getValue() and it will not
give you back the displayed field (Data) but it will give the id.
Sorry for bad formating! Hope it helps
Lets say I have a pair of comboboxes backed by simple remote stores. I need to do some task when either combobox selection changes using selected records (not values).
{
xtype: 'combo',
reference: 'combo1',
store: {
type: 'MyStore1',
},
displayField: 'name',
valueField: 'id',
listeners: {
select: 'onSelect',
},
},
{
xtype: 'combo',
reference: 'combo2',
store: {
type: 'MyStore2',
},
displayField: 'name',
valueField: 'id',
listeners: {
select: 'onSelect',
},
},
//controller
doTask: function(record1, record2){
console.log(record1.data.name, record2.data.name);
},
onSelect: function(combo, record) {
var record1 = this.lookupReference('combo1').getSelection();
var record2 = this.lookupReference('combo2').getSelection();
this.doTask(record1, record2);
},
Now I am trying to trigger doTask() when having only id values, and ended up with something like this:
initData: function(id1, id2){
this.lookupReference('combo1').setValue(id1);
this.lookupReference('combo2').setValue(id2);
var self = this;
var waitTimer = Ext.Function.interval(function(){
var record1 = this.lookupReference('combo1').getSelection();
var record2 = this.lookupReference('combo2').getSelection();
if(record1 && record2){
window.clearInterval(waitTimer);
this.doTask(record1, record2);
}
}, 100, self);
}
Is there a better way?
You should have a look at whether your method works with values that you entered by typing. Not sure about that.
You could also use findRecordByValue wiht getValue. This searches the store using the value that was either chosen by selection or by typing. On the other hand this may come up blank, e.g. if the typed value is not in the store.
I'm using ExtJS 4.1.2, and I have an Ext.grid.Panel with a check-box selection model and a text-box in the header for filtering the items in the grid:
var nameStore = new Ext.data.Store({
...
proxy: { type: 'ajax' ... },
fields: [ { name: 'name', type: 'string' }, ... ],
});
var headerBar = new Ext.toolbar.Toolbar({
xtype: 'toolbar',
dock: 'top',
layout: 'fit',
items: [{
xtype: 'textfield',
...,
listeners: {
change: function(fld, newVal, oldVal, opts) {
var grid = ...;
if (newVal.length > 0)
grid.store.filterBy(function(record, id) { return record.get('name').indexOf(newVal) !== -1; });
else
grid.store.clearFilter()
}
}
}]
});
var nameGrid = new Ext.grid.Panel({
...
selType: 'checkboxmodel',
selModel: { mode: 'SIMPLE' },
store: nameStore,
columns: [ { dataIndex: 'name', flex: true }, ... ],
dockedItems: [ headerBar ],
bbar: [ { xtype: 'tbtext', text: '0 items selected' ... },
listeners: {
selectionchange: function(selModel, selected, opts) {
var txt = ...;
txt.setText(Ext.String.format("{0} items selected", selected.length));
}
}
});
As shown nameStore's filter is applied (or removed) based on the value in headerBar's textbox. Also, a text string in the bottom bar is updated as items are selected/deselected.
Each of these features is working smoothly on its own. But the interaction is giving me trouble: if an item is selected and then gets filtered out, it is deselected and then remains so when the filter is cleared.
How can I maintain the selections (or at least appear to do so to the user) of "hidden" items, either for use elsewhere in my application or to reselect when the filter is cleared? Thanks!
you need not to add the selected grid separately. This can be done in one grid only. Simple method is to have an array variable in page scope and capture the grid select event or itemclick event whatever you want.
e.g if you use select event it will give you your record.
select( this, record, index, eOpts )
you can get your record id and push it to the array variable that you declared.
Once you filtered out the grid. you can loop through the filtered records and call select method by getting selection model.
e.g
grid.getSelectionModel().select(record);
Hope this will help.
I'm working with ExtJS 4.1, I need to create a combo box containing a list of customers and I'd like to set a specific pre-selected item in it, but I don't know how to do it.
Here's the code to create my combo box:
xtype: 'combobox',
fieldLabel: 'customer',
name: 'customer_id',
allowBlank:false,
afterLabelTextTpl: required,
//data store
store: Ext.create('Ext.data.Store', {
autoDestroy: true,
model: 'customer_model',
autoLoad: true,
proxy: {
type: 'ajax',
url: 'load.php?item=customer',
reader: {
type: 'json',
successProperty: 'success',
root: 'data'
}
}
}),
valueField: 'id',
displayField: 'company',
typeAhead: true,
queryMode: 'remote',
emptyText: ''
As you can see my combo box is filled by a data store, that data store is built on a data model called 'customer_model'. Here's the code for data model:
Ext.define('customer_model', {
extend: 'Ext.data.Model',
fields: [
{type: 'int', name: 'id'},
{type: 'string', name: 'company'},
{type: 'string', name: 'vat'},
{type: 'string', name: 'ssn'},
{type: 'int', name: 'ref_id'}
]
});
Well, I'd like to configure my combo box so that a certain item, for instance the customer having id equals to 1, is automatically selected when the page is loaded.
Can anyone help me ?
Thanks in advance.
Enrico.
In Ext.js 3.2.1, you are able to do this:
combobox.setValue(id);
This assumes that the combobox is configured to use id as the valueField. Your code seems to indicate that this is the case. You would also need to have a reference to the id value that you want to set the value to. The caveat here is that you need to make sure that this code only executes after the model is loaded, otherwise the combobox won't have anything to display. You can ensure this by setting the combobox in the callback method of the ajax call or in the load event of the store.
I've looked into the documentation for Ext.js 4.1, and this method seems to still be there. I believe this should do the trick.
Edit: clarity
Thanks to Christopher help I wrote a working version of my code, I've decided to post it here, maybe it could be useful for someone...:
buttons: [{
text: 'Load',
handler: function(){
var form = this.up('form').getForm();
var combobox = form.findField('ref_id_combo');
formPanel.getForm().load({
url: <?php echo "'update_loader.php?id=".$_GET['id']."&item=customer',"; ?>
waitMsg: 'Loading...',
success: function(form, action) {
combobox.setValue(<?php echo get_property_id("ref_id","customer",$_GET['id']);?>);
}
});
}
}
Programatically with combo.setValue(val) or declaratively:
{
xtype: 'combo',
value: val,
...
}
if you want to select the first value of a store you can do
combo.select(combo.getStore().getAt(0))
it will select the value at index 0 of the combo store
If you create your own store first, you can use afterrender: function(combo){}
listeners: {
afterrender: function (combo) {
var record = yourStore.getAt(0);
var abbr= record.get('abbr');
combo.setValue(abbr);
}
}
I'm attemtping to create a custom ComboBox control. The control will have a button on either side of the ComboBox itself, something like this:
[<-] [ --------------- V ] [->]
These buttons will be "next" and "previous" which will allow the user to quickly toggle between options in the dropdown (moving down and up respectively).
I've tried overriding the defaultAutoCreate config of the ComboBox, but I'm getting some odd behavior. Here's what I've tried so far: (this is all inside of a custom class extending ComboBox)
initComponent: function () {
// default ComboBox structure
var comboStructure = {
tag: 'span',
children: [
{ tag: 'a', cls: 'nav prev', html: 'Previous' },
{ tag: 'input', type: 'text', size: '24', autocomplete: 'off' },
{ tag: 'a', cls: 'nav next', html: 'Next' }
]
};
console.log(comboStructure);
var config = {
triggerAction: 'all',
lazyRender: true,
mode: 'local',
store: new Ext.data.ArrayStore({
fields: [
'myId',
'displayText'
],
data: [[1, 'Banner #1'], [2, 'Banner #2']]
}),
valueField: 'myId',
displayField: 'displayText',
defaultAutoCreate: comboStructure
};
Ext.apply(this, config);
IbwUi.controls.PreviewBannerSelectDropdown.superclass.initComponent(this);
}
The 2nd "child" of the comboStructure is actually the default value that gets initialized for ComboBox, I looked at the source code. The code works without error, but there's some odd behavior with the rendering of the combo itself, see here:
Any ideas on how to add my custom elements around the ComboBox when it renders?
Don't do it like this. Instead put all three components into a container class that implements the logic you need.