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.
Related
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
EDIT
It turns out that a store cannot have duplicate IDs. When i remove this field, All records display - which means the grid is not respecting the pageSize
I'm having an issue getting all my store records to display in my grid. The data is returning appropriately from a JSON request, and the pagingtoolbar behaves correctly.
Here's my store:
var store = Ext.create('Ext.data.Store', {
storeId : 'resultsetstore',
autoLoad : false,
model : model,
pageSize : itemsPerPage, // 3
proxy: {
type : 'ajaxwithpayload', //custom ajax proxy to read 'jsonData'
url : 'MCApp',
jsonData: searchquery,
reader: {
type : 'json',
root : 'elements'
}
}
});
I load the store here, and all the correct results are returned:
store.load({
params: { start: 0, limit: itemsPerPage },
callback : function(records, operation, success) {
if(success) {
mainresponse = operation.response.responseText;
if( mainresponse.length == 0 ){
alert('No results returned');
return;
}
var jsonResponse = Ext.JSON.decode(mainresponse);
}
else {
alert('Search Failed: Could not reach the server');
}
And lastly, a simple grid with pagingtoolbar:
var grid = Ext.create('Ext.grid.Panel', {
title: 'Test Data',
store: store,
columns: [{
text: 'Technical Name',
dataIndex: 'tech'
}, {
text: 'ID',
dataIndex: 'element.id'
}, {
text: 'Name',
dataIndex: 'name',
mapping: 'element.name'
}, {
text: 'View',
dataIndex: 'view'
}, {
text: 'Description',
dataIndex: 'description'
}],
dockedItems: [{
xtype: 'pagingtoolbar',
store: store,
pageSize: itemsPerPage,
dock: 'bottom',
displayInfo: true
}],
renderTo: Ext.getBody()
});
The problem here is that not all of my results load into the grid. It seems that when a duplicate ID is encountered, it cuts the results short. That may not be the problem, just my guess
In my logs I see all the data I need returned. In the picture below, I should have 3 rows with the same Element ID 001, however only one is displayed:
Another thing to note is that when I click the Next Button on my pagingtoolbar, the results do not change, and it also reads as a POST on my console. I'm not sure if it's supposed to do that or be a GET?
I used lightning bolts to show how shocking it is that this isn't working
Any ideas?
A very important thing to note is that the server is responsible for paging not ExtJS. The server must not return all rows, but only the rows of the current page. You server side code must take in account the parameters page, start and limit for getting the client side to work.
I think that, beside the duplicated ids, is the main reason for your problems. It is especially the reason, why you see the same data on page one and on page two:
ExtJs asks the server for the data of page 1 and gets all rows. Later, ExtJs asks the server for the data of page 2 and gets again the same rows. This cannot work.
This might be the case when you are giving name property as "id" in the fields array of your Model. try to change that.
I am using the MVC architecture (i have gone through the docs on MVC, but i am still lost here) and i need to know how to populate the records on to my Label. I know that i have to get this done by Stores.
I have loaded the values from the store, but unable to display it on my Panel for some reason. here's my code;
Most of the examples/books demonstrates how to display in a grid, but not a label (I know it has to be the same logic, but i am lost). And it shows how to write to a DB/JSON file and not display the values.
I need to display the COUNTRYNAME in the Label text. This is an example code that i am doing to understand this, can some one help me ?
Ext.define ('ProjectDisplayExample.model.Country',{
extend: 'Ext.data.Model',
//
fields:['countryid','countryname']
//
});
STORE
Ext.define('ProjectDisplayExample.store.Country',{
extend:'Ext.data.Store',
model:'ProjectDisplayExample.model.Country',
remoteGroup:true,
proxy: {
actionMethods : {
read : 'POST',
},
type: 'ajax',
url : '/server/country.php'
}
});
VIEW
Ext.define('ProjectDisplayExample.view.CountryWindow', {
extend: 'Ext.window.Window',
alias: 'widget.countrywindow',
...........
initComponent: function() {
var st = Ext.getStore('Country');
st.load();
this.items = [
{
items: [
{
xtype: 'panel',
region: 'north',
items: [{
xtype: 'label',
// NEED TO DISPLAY COUNTRT NAME FROM THE STORE HERE
}]
}]
}
UPDATE
var store = ... // Your store
store.on('load', function() {
// here store is loaded and you can do anything you want with it
console.log('store is loaded. number of records = ', store.getCount());
}, this, { single: true });
store.load; // I ADDED THIS LINE.................... <---------
UPDATE 2
this.items = [
{
items: [
{
xtype: 'panel',
region: 'north',
items: [{
xtype: 'label',
name : f
}]
}]
I will not post a code sample to exactly solve your question, but I will give you couple points:
Store contains array or records. So you can't just say give me country name from the store. You need first to get a record, for example: var r = store.getAt(0), and only after that you can get countyname field var f = r.get('countryname').
Load() method is asynchronous, so you can just execute it somewhere in the code and assume that for the very next line your store is ready. You need to subscribe to the load event, something like:
var store = ... // Your store
store.on('load', function() {
// here store is loaded and you can do anything you want with it
console.log('store is loaded. number of records = ', store.getCount());
}, this, { single: true });
store.load();
Labels as in xtype: label are actually very rarely used in ExtJs. What exactly are you trying to display in that panel? But anyhow... after you get data out of the store you can use something like update() or setValue() or any other method to update component.
Hope this helps...
I have to fill values in the right multiselect box in an itemselector. First i need to keep it blank and then on selection of an item in the combo box above it, i have to fill values accordingly. I have tried this and its crashing at the moment and nothing seems wrong. Here is the code snippet:
var userList = GetUserList();
var aoiList = GetAOIList();
var userAOIs = "";
var selectedUser="";
var userStore = new Ext.data.ArrayStore({
fields: ['user'],
data: userList
});
var aoiStore = new Ext.data.ArrayStore({
fields: ['aoiList'],
data: aoiList
});
var userAOIStore = new Ext.data.ArrayStore({
fields: ['userAOIs'],
data: userAOIs
});
var aafp = new Ext.FormPanel({
width : 350,
frame : true,
autoHeight : true,
bodyStyle : 'padding: 2px 5px 0 2px;',
labelWidth : 100,
defaults : {
anchor : '95%',
allowBlank : false,
msgTarget : 'under'
},
items : [ {
xtype : 'combo',
fieldLabel : 'Choose User',
emptyText: "Select User...",
id : 'userId',
name : 'user',
multiSelect: false,
store: userStore,
displayField: 'user',
mode: 'local',
editable: false,
typeAhead: true,
triggerAction: 'all',
listeners:{select:{fn:function(combo, value) {
selectedUser = value.get('user');
userAOIs = myAOIs(selectedUser);
userAOIStore = new Ext.data.ArrayStore({
fields: ['userAOIs'],
data: userAOIs});
aafp.getForm().findField("itemselector").reset();
}}
},
value : selectedUser
},{
xtype: 'itemselector',
name: 'itemselector',
fieldLabel: 'AOISelector',
imagePath: 'ext-3.4.0/examples/ux/images/',
drawUpIcon:false,
drawDownIcon:false,
drawTopIcon:false,
drawBotIcon:false,
multiselects: [{
width: 250,
height: 200,
store: aoiStore,
displayField: 'aoiList'
},{
width: 250,
height: 200,
store: userAOIStore,
displayField: 'userAOIs',
valueField: 'userAOIs'
}]
}]
Initially i doubted the "aafp.getForm().findField("itemselector").reset()" call and thought that there might be some other function to dynamically reload the elements in the form, instead of reset which might be used to reset/erase the data in the fields but reset is reloading the contents.
Please provide your inputs how this could be achieved?
Thanks
You can try this:
1) Create the stores.
2) Add the stores to the components
3) When the listener 'selected' is fired get the component who store you would like to dynamical add to and create a new record and add it to the store.
EDIT:
Try something like this (its what I think you want) note the code isn't exact since I'm not sure what exactly you want to do but it should give you an idea of what you need to do.
listeners:{select:{fn:function(combo, value) {
var selectedUser = value.get('user');
var record = Ext.data.Record.create([
'user' : selectedUser
]);
var cmp = Ext.getCmp('compId');//Get the comp that contains the store you want to add to put the cmp id here to look it up
cmp.store.removeAll();//Clear the store
cmp.store.add([record]);//Add the new record into the store
}, this}
Thanks for your inputs, it was helpful.
I found the problem: I was creating a new instance of Ext.data.ArrayStore but the view was linked to the previous instance.
So i used the previous instance, removed everything from it and added new records, jus as theboulderer suggested. But I found that we don't have to catch the handle of itemselector store, it was automatically updated with the modified store.
sample:
var tempUserAOIStore = new Ext.data.ArrayStore({
fields: ['userAOIs'],
data: [['8'], ['9']]
});
userAOIStore.removeAll();
userAOIStore.add(tempUserAOIStore.getAt(0));
userAOIStore.add(tempUserAOIStore.getAt(1));
Now this facility in ArrayStore is also a problem for me as the stores are so tightly binded that if i want to keep the original in some temp store, it is also modified. i.e.
if i do :
B = A;
Itemselector: store = A
A.remove(some records)
I find that B is also modified as A is modified. I am answering here so guess have to post this as a seperate question
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).