I want to use a very simple combo box in ExtJS, but I was surprised to learn that it seems as though I have to complexify things by using a store.
I have a single array of data :
var states = [
{"name":"Alabama"},
{"name":"Alaska"}
]
I create my model 'State' linking to the 'name' field, and then I create my store linking to the model, and the array of data.
Ext.regModel('State', {
fields: [
{type: 'string', name: 'name'}
]
});
var store1 = Ext.create('Ext.data.Store', {
model: 'State',
data: states
});
Now I create my combo, as a field in my panel :
var f = Ext.create('Ext.form.Panel', {
items: [
{
fieldLabel: 'hi there',
xtype: 'combobox',
name: 'XXXX',
store:store1,
maxLength: 64,
allowBlank: false
}
]
})
Nothing tells me that I am doing anything wrong, but I get an 'Uncaught TypeError: Cannot read property 'indexOf' of undefined ' whenever I try and open the combo.
My fiddle is here :
http://jsfiddle.net/sr61tpmd/1/
Another aside to my question is, what is the simplest way I can present a combobox in ExtjS?
As long as you only want a combo box with same value as displayed, it is entirely possible to define the store as an array.
xtype:'combo',
store:['Alabama','Arkansas',...]
A real extjs store is necessary where your displayed text differs from the value. You can see a working example for this (also using the us states, actually) in the ext docs: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.form.field.ComboBox
Related
I have an ExtJS gridanel with a viewmodel store bound to it. The model of that store is a defined model with a field that references another model.
For the sake of simplicity here's an example:
Ext.define('User', {
extend: 'Ext.data.Model',
fields: ['name']
});
Ext.define('Order', {
extend: 'Ext.data.Model',
fields: ['date', {
name: 'user',
reference: 'User'
}]
});
viewmodel: {
store: {
order: {
model: 'Order',
}
}
}
In my gridpanel I have 2 columns. In one column, dataIndex: 'date' works correctly, displaying the date. However, in my second column I want to display the name of the user. I have no idea how to do that. The user field itself is on object so declaring dataIndex: user doesn't work. I tried dataIndex: {user.name} but that doesn't work either. I even tried
bind: {
data: '{user.name}'
}
also to no avail. I have found a solution using renderer config of the column but it is really ugly and beats the point of having a model reference another if I have to manually traverse the data structure for the appropriate field.
TL;DR
I'm looking for a way to declare a column's dataIndex to be a field from a reference model.
UPDATE -
I HAVE ALSO MADE A MOCK IN JSFIDDLE http://jsfiddle.net/mAgfU/371/
AND WITH A FORM PANEL : http://jsfiddle.net/kA6mD/2/
I have the bellow comboox.
When I use the following code to set the form values:
this.form.loadRecord(data);
the entire form is acting ok except from the combo.
instead of giving me the displayField, I get the valueField in the display.
As you can see in the image above, the combo should show the word "Walla" (displayField) instead of "1" (valueField)
Ext.define('App.view.ForeignCombo', {
extend: 'Ext.form.ComboBox',
alias: 'widget.foreigncombo',
queryMode: 'local',
displayField: 'Name',
valueField: 'Id',
editable: false,
matchFieldWidth: false,
constructor: function(config) {
Ext.apply(this, config);
Ext.define('BrnadComboModel', {
extend: 'Ext.data.Model',
fields: ['Id', 'Name']
});
this.store = Ext.create('Ext.data.Store', {
model: 'BrnadComboModel',
autoLoad: true,
proxy: {
type: 'ajax',
url: '/api/Brand/',
reader: {
type: 'json',
root: 'Results'
}
},
pageSize: 50,
});
this.callParent();
}
}
);
this is how I use it:
{
"xtype": 'foreigncombo'
, "name": 'Brand.Id'
, "fieldLabel": 'Brand.Id'
}
There is no race bewtween the form display and the combo ajax request, the combo store is autoLoad:true, meaning I see that it has already been loaded...
Thanks
I used your fiddle a an example. Place a breakpoint in line 87 (Ext.ComponentQuery.query('comobobox')....), in this fiddle http://jsfiddle.net/kA6mD/9/, and set a watch to Ext.ComponentQuery.query('combobox')[0].store.data.. you'll notice the store has no data. This may be linked to what I mentioned in the comment.
I know there must be a better way of doing this, but what I usually use as a workaround is either load the store at some point before in the app or use a synchronous Ext.Ajax.request and load each record at a time in the store.
As this is a combo for brands I suppose you could load the store before (i.e. app load) and lookup for the store instead of creating a new one each time you create a foreigncombo component, so the first solution should work.
As for the second workaround it should also work, it takes a little bit more coding but its actually pretty easy. It should look something like this...
Ext.Ajax.request({
url:'your/url/',
async:false,
.....
success:function(response){
var records = Ext.JSON.decode(response.responseText);
for(var m=0; m<records.length; m++){
var record = Ext.create('YourBrandModel',{
abbr:records[m].abbr,
name:records[m].name
});
store.add(record);
}
}
})
You should do this as few times as possible as it may slow down the user experience if it gets called everytime you create a "foreigncombo", so checking if this store exists before creating one might be a good idea.
Please take in cosideration that I have not tested this code, so you may have to tweak it a little in order for it to work. But it should get you on tracks.
I need to pick up Ext JS for a project I working on, and here's a simple issue that got surfaced in it which I can't figure out:
Here's my code:
var arrayData = [
['Jay Gar','MD'],
['Aaron Baker','CA'],
['Susan Smith','NY'],
['Mary Stein','KT'],
['John Zalupic','WA'],
];
var store = Ext.create('Ext.data.ArrayStore',{
data: arrayData,
fields: ['personName', 'state']
});
var grid = Ext.create('Ext.grid.Panel', {
title: 'first grid',
renderTo: Ext.getBody(),
authoHeight:true,
width: 250,
store: store,
autoScroll: true,
columns: [
{ header: 'name', dataIndex: 'personName' },
{ header: 'st', dataIndex: 'state', sortable: false }
]
});
grid.getSelectionModel().on('selectionchange', function(sm, selectedRecord){
var newData = [
['Poka Boka', 'VK'],
['Choko Mok', 'CA']
];
store.removeAll();
store.add(newData);
});
So basically I populate the grid with default values and whenever one of them is clicked, data in the store is getting replaced with new data, which should in turn prompt re-render of the Grid Panel. It does work, but with one consistent issue:
When I click on any element, the newData values flash below the data it's about to replace and for some reason it shows 3 rows: first one, second one and then first one again. Also, I get an error saying "Uncaught TypeError: Cannot read property 'internalId' of undefined" happening on this line: store.add(newData).
Any idea what might be causing it? I'm using Ext JS 4.
Thank you!
Luka
The add method is expecting records and you are passing an Array.
You should create an instance of your store record type and iterate to create as many records as you need and then add them to the store.
here is an example:
var store=this.getStore();
var rt = store.recordType;
var p = new rt({
InvoiceLineNum: '',
LineNumber:'',
ItemDescription: '',
Quantity: '',
UnitPrice: '',
UnitMeasure:'',
TotalAmount:'',
OrderDate:new Date()
});
this.stopEditing();
store.insert(count, p);
this.startEditing(count, 0);
this.markEditableCells(count);
I use the insert here but you can use the add just as well.
Is there a working example available of an ext js ListFilter where the list options are loaded by a remote store. The documentation gives examples of harcoded options like 'Small', 'Medium' and 'large'.
I wish to load these options from a remote store. I found one example here but this modifes the core class ListFilter.js I am looking to avoid that.
http://www.sencha.com/forum/showthread.php?64234-Ext.ux.grid.filter.ListFilter-gt-loaded-store
Thanks,
Kaushik
Here is an example for a filter. The following code snippet would be used in the instantiation block for your filter plugin.
filters: [{
type: 'list',
dataIndex: 'dataInTheStoreName', // use this as the value
single: false, // true for radio buttons
labelField: 'dataInTheStoreLabel', // use this as the label
store: new yourExampleStore()
}.{...your other filters...}]
So just make an ExtJs store object to access your data, and attach it to the list filter.
There are many example of this such as here.
I've created a working fiddle that could be useful for you:
https://fiddle.sencha.com/#view/editor&fiddle/2gp6
Basically you declare the filter with a store (list filter needs boths: lavel and id)
text: 'Eye Color',
dataIndex: 'eyeColor',
filter: {
type: 'list',
store: filterStore,
idField: 'id',
labelField: 'value'
}
I am trying to create my own Date/Time field. I know there are a few that others have made, I'm making my own .
My question is as follows. I want to create a new object, DateTime, which extends Ext.Panel. I specify some properties for width, height, etc but I also specify the values for the items property which will contain a date field and a time field. When I try to actually instantiate the created object, I get an error saying "Object or property not supported". When I go into the error, it seems that the items collection throws an error The code is as follows:
var dateField = new AppealDate({
id: 'dateField',
tabIndex: 0,
fieldLabel: '',
msgTarget: 'under'
});
var timeField = new Ext.form.TimeField({
id: 'timeField',
tabIndex: 0,
fieldLabel: '',
msgTarget: 'under'
});
var DateTime = Ext.extend(Ext.Panel, {
id: '',
xtype: 'panel',
fieldLabel: '',
layout: 'table',
layoutConfig: {
columns: 2
},
items: [dateField, timeField]
});
var dateTimeField = new DateTime(); //this throws an error
Your class is missing initComponent. You also need to render the panel somewhere.
DateTime = Ext.extend(Ext.Panel, {
initComponent: function() {
// define dateField, timeField here.
this.dateField = new AppealDate({
id: 'dateField',
msgTarget: 'under'
});
this.timeField = new Ext.form.TimeField({
id: 'timeField',
msgTarget: 'under'
});
Ext.apply(this, {
items: [this.dateField, this.timeField]
});
DateTime.superclass.initComponent.call(this);
}
});
var dateTimeField = new DateTime();
dateTimeField.render(Ext.get('someDiv'));
As a comment outside of your direct question, "DateTime" is a terrible name for a Panel subclass. You want someone coming along later to know what kind of class they are dealing with -- "DateTimeField" would be much better, based on how you're using it (although that implies a Field subclass as explained below...).
However, note that another potential issue since you are intending to use this Panel as a Field is that a FormPanel is going to expect its form fields to support the Ext.form.Field interface, which your "field" will not (i.e., you won't be able to add your DateTime object into a form's items config). So if your goal is to create a truly reusable component that can be treated as a Field, you're going to want to add methods like getValue, setValue, markInvalid, etc. that internally interact with your constituent fields. It's not a trivial task to get it all working smoothly.
(Not sure if this is your goal, but thought I would mention it since I've gone down this road myself).