I'm seeing an issue with a combobox where I have a listener for the 'change' event. When the event fires it runs a function that filters a store that powers another combobox to filter the values that are available in the 2nd combobox.
The idea is that when you pick from a short list in the first combobox, it pares down the choices in the second combobox.
When the form loads, you can click the second combobox and see all the choices, that works great. When you then select something in the first combobox and then click the second combobox again, you see the appropriate shortened list but it's grayed out and the 'loading...' thing just spins and will never go away.
If you load the form and pick something in the first combobox and then click the second combobox it will filter and show fine but you run into the issue of the loading problem I described above if you try to change your selection in the first box and click the second combobox again.
Please see the code below, I have this setup working on another screen and it doesn't seem to have this issue.
I've got an ext store created like the following:
var comboBreaker = Ext.create('Ext.data.Store', {
autoLoad: false,
remoteSort: true,
remoteFilter: true,
fields: [{
name: 'id',
mapping: 'item_id',
type: 'int',
useNull: false},
'item_display_number','item_name', 'line_item_type_id', 'item_description'
],
proxy:{
type:'ajax',
url: '/invoicer/data/getlineitems',
reader: {
type: 'json',
successProperty: 'success',
root: 'results',
totalProperty: 'totalCount'
},
sorters:[{
property:'item_display_number',
direction:'ASC'
}]
}
});
This store powers a combobox, like so:
Ext.define('Writer.Form', {
extend: 'Ext.form.Panel',
alias: 'widget.writerform',
requires: ['Ext.form.field.Text'],
initComponent: function(){
this.addEvents('create');
Ext.apply(this, {
activeRecord: null,
frame: true,
title: 'Line Item',
id: 'writerform',
fieldDefaults: {
anchor: '100%',
labelAlign: 'right'
},
items: [{
xtype: 'combobox',
fieldLabel: 'Item #',
name: 'item_number',
store: comboBreaker,
displayField: 'item_display_number',
valueField: 'id',
allowBlank: false,
forceSelection: true
},{
xtype: 'combobox',
fieldLabel: 'Item Type',
name: 'item_type',
id: 'item_type',
displayField: 'line_item_type',
valueField: 'id',
store: invoicer_lineItemTypeStore,
forceSelection: true,
labelWidth: 75,
width: 200,
listeners: {
change: {
fn: function() {
itemNumberFilter(comboBreaker);
}
}
}
}]
});
The itemNumberFilter() function takes a store and does filtering on it, here is that code:
function itemNumberFilter( store ) {
var id = Ext.getCmp('item_type').getValue();
store.remoteFilter = false;
store.clearFilter();
if ( id ) {
store.filter('line_item_type_id', id);
}
store.remoteFilter = true;
store.removeAll();
store.load({
scope: this,
callback: function( records ) {
console.log('Loaded records!');
console.log(records);
}
});
}
I see the logged out records every time I change my selection in the first combobox and I can 'see' the results in the second combobox but they're always grayed out with the 'loading..' GIF showing.
Edit: Video example: http://screencast.com/t/cUSHyFE6FIV
Edit: I believe this is the solution:
lastQuery: '',
listeners: {
beforequery: {
fn: function(query) {
delete this.lastQuery;
}
}
}
Adding this to the combobox config fixes the issue.
Edit2: I ran into a second bug introduced by this, it was fixed by adding:
this.clearValue();
to the beforequery function (above delete this.lastQuery). This clears the value of the combobox each time the drop down arrow is clicked.
Let's say you select item x in combo_1 and then item a in the pared down list in combo_2. You then change the selection in combo_1 to y, which then changes the list of items again in combo_2. Is a available in the new list in combo_2 that results from selecting item y in combo_1? Maybe it is an issue of trying to keep an item selected when it no longer exists in the list available to the combo.
Have you tried clearing the selection in combo_2 before applying the filter?
You can dynamically load the store of the second combox box but be sure to set the second combox box to "local".
Related
I have a combo box with the multiSelect property and I want to know how can I know how many items were selected. I tried with:
combobox.store.getCount();
but it tells me the total of items in my combo box instead of the total of items selected by the user. Basically I want to make a condition that will trigger when the user selects more than one option in the combobox
You can use combo.getPicker() method and picker have method to get selected records
In this FIDDLE, I have created a demo using combobox with multi-select. I hope this will help you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
// The data store containing the list of states
Ext.create('Ext.data.Store', {
fields: ['abbr', 'name'],
storeId: 'states',
data: [{
"abbr": "AL",
"name": "Alabama"
}, {
"abbr": "AK",
"name": "Alaska"
}, {
"abbr": "AZ",
"name": "Arizona"
}]
});
// Create the combo box, attached to the states data store
Ext.create('Ext.panel.Panel', {
title: 'Combo Example',
renderTo: Ext.getBody(),
items: [{
xtype: 'combo',
margin: 10,
fieldLabel: 'Choose State',
store: 'states',
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
multiSelect: true,
}],
bbar: ['->', {
text: 'Get Selected',
handler: function () {
var selectionModel = this.up('panel').down('combo').getPicker().getSelectionModel();
record = selectionModel.getSelection();
console.log(record);
Ext.Msg.alert('Info', 'Number of Selected record is ' + selectionModel.getCount());
//Ext.Msg.alert('Info', 'Selected record is <br> '+ record.map(r=>{return r.get('name')}).join('<br>'));
}
}]
});
}
});
Here is a possible solution. Go to multiselect-demo.html, open your browser console (F12 on Google Chrome and Firefox) and type :
f = Ext.getCmp("multiselect-field");
f.on("change", function () {
console.log(this.getValue().length)
});
Then see what's happening when you change the selected values in the "MultiSelect Test". For more informations, see : http://docs.sencha.com/extjs/4.2.5/#!/api/Ext.ux.form.MultiSelect-method-getValue.
ExtJS 5
I have a grid and it has 3 columns (Id, Students,Selected Students). In column2 (Students), I have bind static data. When i click on any item of second column then this record should be added in column3 (Selected Students) in current record or row. I have one button also called (Add new item) used for creating new row dynamically.
Note - When i add a new row by clicking on Add new item button, then new row will be added and 3 column(Selected Students) value should be blank.
I have tried so much but didn't get solution. The main problem is that when i bind data in third column then it binds proper, but when i add a new row, it also shows in new record also but it should not be. If i clear store or combo item, then it removes from all rows instead of current record/row.
Ext.onReady(function () {
var comboStore1 = Ext.create('Ext.data.Store',
{
fields: ['text', 'id'],
data:
[
{ "text": "Value1", "id" :1 },
{ "text": "Value2", "id": 2 },
{ "text": "Value3", "id": 3 }
]
});
var comboStore2 = Ext.create('Ext.data.Store',
{
fields: ['text', 'id']
});
var gridStore = Ext.create('Ext.data.Store',
{
fields: ['id', 'students', 'selectedStudents'],
data:
[
{ "id" : 1},
]
});
var window = new Ext.Window({
id: 'grdWindow',
width: 400,
height: 200,
items: [
{
xtype: 'panel',
layout: 'fit',
renderTo: Ext.getBody(),
items: [
{
xtype: 'button',
text: 'Add New Item',
handler: function () {
var store = Ext.getCmp('grdSample').store;
var rec = {
id: 1,
students: '',
selectedStudents: ''
}
store.insert(store.length + 1, rec);
}
},
{
xtype: 'grid',
id: 'grdSample',
store: gridStore,
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
})
],
columns: [
{
header: 'id',
dataIndex: 'id'
},
{
header: 'Students',
dataIndex: 'students',
editor: {
xtype: 'combobox',
store: comboStore1,
displayField: 'text',
valueField: 'text',
queryMode: 'local',
listeners: {
select: function (combo, records) {
var rec = records[0].data;
}
}
}
},
{
header: 'Selected Students',
dataIndex: 'selectedStudents',
editor: {
xtype: 'combobox',
id: 'combo2',
store: comboStore2,
displayField: 'text',
valueField: 'id'
}
}
]
}
]
}]
}).show();
});
I have tried almost everything but still i didn't get any solution. In another way - How to insert a value in grid editor combo only in current row. (Another row should not be reflected). If another row is being reflected, then how to remove value before rendering from another row without reflecting other rows.
Well, I guess main problem is that you trying to change certain grid row editor component while it suppose to be same for all grid rows.
The main problem is that when i bind data in third column then it binds proper, but when i add a new row, it also shows in new record also but it should not be. If i clear store or combo item, then it removes from all rows instead of current record/row.
It happens because all grid row editors use same store instance, comboStore2, and when you change its data you change it for all editors.
To create separate store for each editor you have to do something like this:
{
header: 'Selected Students',
dataIndex: 'selectedStudents',
editor: {
xtype: 'combobox',
id: 'combo2',
store: Ext.create('Ext.data.Store', {
fields: ['text', 'id']
}),
displayField: 'text',
valueField: 'id'
}
}
But than its become not trivial to select specific row editor component and its store.
I recommend you to take a look at Ext.grid.column.Widget as you can bind certain row (its record actually) to widget with its onWidgetAttach property.
Your second column is dummy.
You could directly use a tagfield component as the editor for your third column, which lets you select multiple values.
And you'll need a single store for the list of all students.
I have this code ...
Ext.define("Requestor.view.main.RequestGrid", {
extend: 'Ext.grid.Panel', // Our base class. A grid panel.
... lots of code ...
columns: [
... some more code ...
{
text: 'Status',
dataIndex: 'status',
renderer: function(value, metaData) {
metaData.tdStyle = (value == 'Ready') ?
'color:green;font-weight: bold' :
'color:red;font-style: italic'
return(value)
},
filter: { type: 'list', value: 'Ready' },
flex: 1
}
... more code ...
This works great when the page initially loads, and if I manually, through the UI, change the filters to include other rows that do not have the value 'Ready' then appear. (see screen shot)
But if I try to change the sorting on my Status column the filter automatically changes back to just showing rows that have a status value of 'Ready'. (see screen shot)
Is this a bug or I am doing something wrong?
Thanks!
I use filters of list type as follows->
{
type: 'list',
dataIndex: 'indexName',
labelField: 'name',
store: Ext.create('MyStore')
}
As per the requirement, I have a panel which contains grid and two buttons:
Grid Columns: ID, Name, Timezone
Buttons: Add, Save
I have switched on Cell editing for the grid.
Editor for ID - Textfield (Textfield id: IDEdit)
Editor for Name: Textfield (Textfield id: NameEdit)
Editor for Timezone: Textfield (Textfield id: TimezoneEdi)
Now when I click on Add, I add one BLANK row at the top with Blank ID, Name and Timezone so that user can add the record.
But I do not want user to edit ID if he is not adding the new row. Meaning when he double clicks on ID even if it has editor defined, I want it disabled.
So I have kept IDEdit as disbled in the beginning. On click of add I am making it enabled. Once user inputs data nad clicks on Save, I again make IDEdit as disabled. This works fine.
But now when I edit only Name and click Save, it says that cannot define disable property of undefined. This is happening because EditID has not been created yet.
Code is as below:
xtype: 'gridpanel',
height: 308,
id: 'MyGrid',
scrollable: true,
store: 'MyStore',
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'ID',
text: 'ID',
flex: 1,
editor: {
xtype: 'textfield',
disabled: true,
id: 'IDEdit'
}
},
{
xtype: 'gridcolumn',
dataIndex: 'Name',
text: 'Name',
flex: 1,
editor: {
xtype: 'textfield'
}
},
{
xtype: 'gridcolumn',
dataIndex: 'TIMEZONE',
text: 'TimeZone',
flex: 1,
editor: {
xtype: 'textfield'
}
}
On Save button:
Ext.Ajax.request({
Ajax request to server
},
success: function(response) {
var status = response.responseXML.getElementsByTagName('Row')[0].childNodes[0].childNodes[0].nodeValue;
var message = response.responseXML.getElementsByTagName('Row')[0].childNodes[1].childNodes[0].nodeValue;
if(status === '1'){
store.removeAll();
store.load();
Ext.getCmp('IDEdit').disable();
}
else{
Ext.Msg.alert('Failure', message);
}
}
});
}
How can I avoid this error? How can I check whether IDEdit exists or not before making it enable/disable?
Thanks !
First, using id as identificator in big application is very bad idea since you need to watch about unique id on every component in your application.
Better solution is using itemId.
So it should be something like this:
editor: {
xtype: 'textfield',
disabled: true,
itemId: 'IDEdit'
}
Then you could check whatever component exists in this way:
var components = Ext.ComponentQuery.query('gridpanel > gridcolumn > textfield[itemId=IDEdit]');
if(!Ext.isEmpty(components)){
//which is working
//components[0].setDisabled(true);
//or
//components[0].disabled()
}
My suggestion would be not to define any editor for 'ID' column in this situation. When you click on Add button, create a record with new unique ID or set default value '-1' (negated values[-1,-2,-3,...,-n] if u are doing multi add action) and insert it on top like you are doing. Set the other values like you are doing already.
I am trying to populate a combobox with a list of Project names. I am able to successfully get all Project names, but I cannot seem to figure out how to add them as a custom set of data to a combobox. I have looked into using the other types of comboboxes (Iteration, Portfolio, Attribute, etc), but they don't seem to have the capabilities to add custom data to their drop down list (unless I am mistaken). Here is the code that I am using for my combo box:
this.down = this.add({
xtype: 'rallycombobox',
storeConfig: [{
model: 'Project',
autoLoad: true,
fieldLabel: 'Projects:',
data: this.project_names,
width: field_width
}]
});
When trying to run with this code, I get a "Uncaught TypeError: Cannot call method 'getProxy' of undefined. I cannot figure out how to get it to work. I have also tried it with the following:
this.down = this.add({
xtype: 'rallycombobox',
model: 'Project',
fieldLabel: 'Projects:',
data: this.project_names,
width: field_width
});
I still end up with the same error. Can anyone help me with what I am doing wrong? Thanks!
If you already have a list of Projects in hand that you'd like to use in a ComboBox, instead of a Rally ComboBox I'd recommend just using the Ext ComboBox. The Rally ComboBox is designed to populate its store by querying the data from rally - thus the getProxyerror you are seeing when trying to mix and match the Rally WSAPI store with local data.
The setup might look something like the following.
// The data store containing the list of Projects
var projectStore = Ext.create('Ext.data.Store', {
fields: ['_ref', 'Name'],
data : [
{"_ref": "/project/12345678910", "Name": "Project 1"},
{"_ref": "/project/12345678911", "Name": "Project 2"},
{"_ref": "/project/12345678912", "Name": "Project 3"}
//...
]
});
// Create the combo box, attached to the Projects data store
this.projectSelector = Ext.create('Ext.form.ComboBox', {
fieldLabel: 'Choose Project',
store: projectStore,
queryMode: 'local',
displayField: 'Name',
valueField: '_ref',
listeners:{
scope: this,
select: function(combobox) {
// Do stuff here
console.log('Ref of Project Selected: ' + this.projectSelector.getValue());
}
}
});
this.down('#projectSelectorContainer').add(this.projectSelector);
Hopefully this is helpful. Let us know if there's follow-on questions.
This might help you:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
//Write app code here
var projectStore = Ext.create('Rally.data.WsapiDataStore',{
model: 'project',
fetch: ['Name','ObjectID'],
autoLoad: true,
// filters:[{
// property:'ObjectID',
// operator:'=',
// value: __PROJECT_OID__
// }],
listeners:{
load: function(store,records,success){
this._updateCombo(store);
},
scope: this
}
});
console.log('/project/',__PROJECT_OID__);
},
_loadCombo: function(myStore){
this._myCombo = Ext.create('Ext.form.ComboBox',{
fieldLabel: 'Choose Project',
store: myStore,
queryMode: 'remote',
displayField: 'Name',
valueField: 'Name',
listeners: {
select: function(combobox,records){
console.log(records[0]["data"]["Name"]);
}
},
scope:this
});
this.add(this._myCombo);
},
_updateCombo: function(myStore){
if(this._myCombo === undefined){
this._loadCombo(myStore);
}else{
this._myCombo.clearValue();
}
}
});