Where's my EXT JS 4 model data? - extjs

Using Ext JS 4.1....
I have a grid that displays a bunch of Model instances, although only some of the fields are displayed. I then have a double-click listener where I would like to load the entire record into a form for editing. In the double-click listener I do not see the data in my hasMany association although the json data is being returned according to Firebug's Net display where I see the response from the server call. Is there something wrong with my model or am I going about this wrong?
Request.js
Ext.define('Request', {
extend: 'Ext.data.Model',
requires: ['PointOfContact'],
fields: [
{name: 'id', type: 'int'},
{name: 'project', type: 'string'},
{name: 'purpose', type: 'string'},
{name: 'status'},
{name: 'additionalInfo', type: 'string'}
],
hasMany: [{
model: 'PointOfContact',
name: 'pointOfContacts',
foreignKey: 'id',
associationKey: 'pointOfContacts'
}],
proxy: {
type: 'rest',
url: '/web/project/rest/request/',
reader: { type: 'json' },
writer: { type: 'json' }
}
});
PointOfContact.js
Ext.define('PointOfContact', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'int'},
{name: 'fullName', type: 'string'},
{name: 'email', type: 'string'},
{name: 'phone', type: 'string'}
]
});
Requests.js
Ext.define('Requests', {
extend: 'Ext.data.Store',
model: 'Request',
autoLoad: true
});
RequestsView.js
Ext.define('RequestsView', {
extend: 'Ext.grid.Panel',
title: 'All Requests',
store: 'Requests',
viewConfig: {
singleSelect: 'true',
listeners: {
itemdblclick: function(dataview, record, item, index, e) {
console.log(record.get('project'));
console.log(record.get('purpose'));
console.log(record.get('status'));
console.log(record.get('additionalInfo'));
console.log(record.get('pointOfContacts'));
var comp = Ext.ComponentQuery.query('requestForm');
comp[0].getForm().loadRecord(record);
var mainPanel = Ext.ComponentQuery.query('mainpanel');
mainPanel[0].getLayout().setActiveItem('requestForm');
}
}
},
columns: [
{header: 'Project', dataIndex: 'project', flex: 1},
{header: 'Purpose', dataIndex: 'purpose', flex: 1},
{header: 'Status', dataIndex: 'status', flex: 1}
]
});
So in the console I see the values for project, purpose, status and additionalInfo but I get "undefined" for pointOfContacts.
Any suggestions?
UPDATE WITH FINAL WORKING CODE:
Here is the working code I used to retrieve the pointofContacts and load a grid on my form panel with the pointOfContacts
...
itemdblclick: function(dataview, record, item, e) {
var comp = Ext.ComponentQuery.query('requestForm');
comp[0].getForm().loadRecord(record);
Ext.getCmp('pocGrid').reconfigure(record.pointOfContacts());
var mainPanel = Ext.ComponentQuery.query('mainpanel');
mainPanel[0].getLayout().setActiveItem('requestForm');
}
....

Has many associations are not parsed in to associated records by default. Especially for the grid - as that is supposed to be a flat data view. Model docs show you how to setup associations but don't say anything about creating instances for you :)
There are links to usage of has many (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.data.association.HasMany) from the Model docs. Unfortunately the usage is not what you expect it to be. Essentially it is designed to fetch the records on demand by calling their store to load.

Related

ExtJS localstorage proxy model/store issue

I'm using ExtJS 5.1.0 and running into a strange problem.
I have the following model:
Ext.define('cardioCatalogQT.model.Load', {
extend: 'Ext.data.Model',
config:{
idProperty: 'id',
fields: [
{name: 'key', type: 'string'},
{name: 'comparator', type: 'string'},
{name: 'value', type: 'string'},
{name: 'type', type: 'string'}
]
}
});
And the Store:
Ext.define('cardioCatalogQT.store.Payload', {
extend: 'Ext.data.Store',
alias: 'store.Payload',
// add package.framework=ext to .sencha/app/sencha.cfg
config:{
model: 'cardioCatalogQT.model.Load',
storeId: 'Payload',
autoLoad: true,
proxy: {
type: 'localstorage'
}
}
});
When I add a record to the store:
var payload = Ext.create('cardioCatalogQT.store.Payload');
payload.add({
type: 'dx',
key: item.data.code,
comparator: 'eq',
value: item.data.description
});
payload.sync();
The data in localstorage look like all the records except for #7 and #11 in the attached image
However, when I add the field elements to the store like this:
Ext.define('cardioCatalogQT.store.Payload', {
extend: 'Ext.data.Store',
alias: 'store.Payload',
// add package.framework=ext to .sencha/app/sencha.cfg
config:{
idProperty: 'id',
fields: [
{name: 'type', type: 'string'},
{name: 'key', type: 'string'},
{name: 'comparator', type: 'string'},
{name: 'value', type: 'string'}
] ,
//model: 'cardioCatalogQT.model.Load',
storeId: 'Payload',
autoLoad: true,
proxy: {
type: 'localstorage'
}
}
});
I get the desired results in 7 and 11.
One other issue, is instead of giving an actual name to the model record, I get the very not useful name of ext-data-proxy-localstorage-N for the model instance.
Also, I am getting this error when referencing the model via the store:
[Error] Failed to load resource: the server responded with a status of 404 (Not Found) (cardioCatalogQT.model.Load, line 0)
I have done a sencha app build and no errors were thrown.
Any idea as to what I am doing wrong (I am basically doing what I've done with Sencha Touch, where I had much success)? Is this a bug, perhaps?
Issue was for ExtJS, to get the desired name on the store, you have to specify and id in the proxy:
proxy: {
type: 'localstorage',
id : 'payload'
}
Now, the model instances in my localstorage are showing up as desired, and I can query them using standard methods, like findRecord. Good times!
Moral of the story: ExtJS has different behaviors than Touch

Extjs 4 Combobox data store can't show data

I am using Extjs 4.1, tried to load data for Combobox, but doesn't work. I have strong doubt about hte json reader root / record.
the data model and store are defined ,
Ext.define('tagModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'string'},
{name: 'name', type: 'string'}
]
});
var tagStore = new Ext.data.Store({
model: 'tagModel',
proxy: {
type: 'ajax',
url: '/ExtjsWebApp/webresources/question/loadTags',
reader: {
type: 'json',
record : 'rtnList'
}
},
listeners: {
load: function(store, records, options){
alert("success " +records.length);
}
},
autoLoad: true
});
the ComboBox is defined as this,
{
itemId: 'search_tag_fld',
fieldLabel: 'Tag',
xtype: 'combobox',
displayField: 'name',
valueField: 'id',
store: tagStore,
queryMode: 'remote',
multiSelect: true,
anchor: '100%',
labelHeight: 300
}
I am sure that the restful webservice will return data as this
{"rtnList":[{"id":1,"name":"Java","active":"true"},{"id":2,"name":"J2EE","active":"true"},{"id":3,"name":"JMS","active":"true"},{"id":4,"name":"Design","active":"true"},{"id":5,"name":"SOA","active":"true"}],"successMsg":"success","errorMsg":"","time":"09/21/2013 18:34:55","sessionId":null,"userId":null}
In your reader, change "record" to "root". Here's a fiddle that shows that your current setup will work just fine: https://fiddle.sencha.com/#fiddle/km

Load data to form in mvc

In my appliacation , I have a list and detail(form).I want to load data to Detail view(set data to textfields of form) when list item is clicked. For both list and detail, I am getting data from remote server. I am following MVC.
Now, When listItem is clicked, I am able to get data from server and save it to store and also showing detail view. But I am not able to bind data from store to textfields in form.
Model
Ext.define('App.model.Details', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'Name', type: 'string'},
{name: 'BillingStreet', type: 'string'},
{name: 'BillingCity', type: 'string'}
]
}
});
Store
Ext.define('App.store.Details', {
extend: 'Ext.data.Store',
config: {
model: 'App.model.Details',
autoLoad :true,
grouper : function(record) {
return record.get('Name')[0];
},
}
});
list view
Ext.define('App.view.View', {
extend: 'Ext.List',
alias:'widget.contactlist',
fullscreen: true,
id: 'contactlist',
config:{
disableSelection:true,
store:'Contacts',
itemTpl:'{Name}',
items:[
{
xtype:'toolbar',
docked:'top',
title:'Leeds List'
}
]
}
});
Detail view
Ext.define("App.view.ListDetail", {
extend: "Ext.form.Panel",
requires: "Ext.form.FieldSet",
alias: "widget.listDetail",
config:{
scrollable:'vertical'
},
initialize: function () {
this.callParent(arguments);
var topToolbar = {
xtype: "toolbar",
docked: "top",
title: "Details"
};
this.add([
topToolbar,
{ xtype: "fieldset",
items: [{
xtype: 'textfield',
store: 'Details',
value : 'Name',
label: 'Name'
},
{
xtype: 'emailfield',
store: 'Details',
value : 'BillingStreet',
label: 'Email'
},
{
xtype: 'passwordfield',
store: 'Details',
value : 'BillingCity',
label: 'Password'
}
]
}
]);
}
});
Controller
Ext.define('App.controller.Main', {
extend: 'Ext.app.Controller',
config: {
refs: {
// We're going to lookup our views by xtype.
contactlist: "contactlist",
contactdetail: "listDetail",
//f_name:"#f_name"
},
control: {
contactlist: {
// The commands fired by the notes list container.
itemtap: "oneditLeadCommand"
}
},
routes: {
'contactlist': 'activateList'
}
},
activateList: function ()
{
Ext.Viewport.animateActiveItem(this.getContactlist(), this.slideRightTransition);
},
slideLeftTransition: { type: 'slide', direction: 'left' },
slideRightTransition: { type: 'slide', direction: 'right' },
oneditLeadCommand: function (list, index, target, record, e, eOpts)
{
console.log("onEditLead"+record.data.Id);
this.activateLeadDetail(record);
},
activateLeadDetail: function (record)
{
var contactDetail = this.getContactdetail();
//console.log("activateLeadDetail"+contactDetail.textfield);
//contactDetail.setRecord(record); // load() is deprecated.
//this.getF_name().setDisplayField("");
store = Ext.StoreMgr.get('Details');
//console.log("activateLeadDetail"+store);
store.setProxy({
type: 'ajax',
url : 'http://10.0.2.2:8080/SalesForce/leads/get-lead-details/00D90000000jvoU!AR4AQB6Xcjz4UNBKf12WOcYHWc31QxK2.fXTcbCvOq.oBosCrjBezhqm8Nqc1hrf8MKK5LjLAu8ZC5IqB1kdpWvJGLdWd5pJ/'+record.data.Id, // the json file that holds all our contact info.
reader: {
type: 'json'
}
});
store.load();
var record1 = Ext.StoreMgr.get('Details').getAt(0);
console.log("activateLeadDetail"+record1);
Ext.StoreMgr.get('Details').each(function(test){
console.log("for loop"+test.data);
});
contactDetail.setRecord(record1);
Ext.Viewport.animateActiveItem(contactDetail, this.slideLeftTransition);
},
// Base Class functions.
launch: function () {
this.callParent(arguments);
console.log("launch");
},
init: function () {
this.callParent(arguments);
console.log("init");
}
})
Please help to bind data to detail view.
So I'm guessing your Contacts Store is defined somewhere else but since this one is working you didn't paste the code here.
So one quick note on the model, where you should always define an idProperty. This is what Sencha use internally to define the "primary key" on your store and therefore work properly when you reload/refresh your store.
Ext.define('App.model.Details', {
extend: 'Ext.data.Model',
config: {
idProperty: 'Name', // Or something from your server maybe?
fields: [
{name: 'Name', type: 'string'},
{name: 'BillingStreet', type: 'string'},
{name: 'BillingCity', type: 'string'}
]
}
});
Secondly, why did you use the initialize method in your ListDetail view when you used the config method in your listView? if you specify the config instead, you will be able to to reuse some of this component in a more easy way somewhere else by doing something like
items: [
{
xtype: 'ListDetail',
anyOtherAttribute: value
}
]
But that's kinda out of scope here. But anyway. So what is wrong here I think is that you have defined a Store for each field of your panel. I'm sorry i can't test my hypothesis, but here is what I would do:
Ext.define("App.view.ListDetail", {
extend: "Ext.form.Panel",
requires: "Ext.form.FieldSet",
alias: "widget.listDetail",
config:{
scrollable:'vertical'
items:[
{
xtype: "toolbar",
docked: "top",
title: "Details"
},
{
xtype: "fieldset",
itemId: 'detailedListFiledset', //Overall, prefer itemId
items: [
{
xtype: 'textfield',
value : 'Name',
label: 'Name' // may be you want placeholders here?
},
{
xtype: 'emailfield',
value : 'BillingStreet',
label: 'Email' // and here..
},
{
xtype: 'passwordfield',
value : 'BillingCity',
label: 'Password' // and here..
}
]
}
]
}
});
Alright, and now the issue seems to be in your controller:
Add a ref to your fieldset
Add a reference to your store
create a afterload callback when your store is loaded (Details)
Either clear the store every time or append data and apply to filter to get the correct record (this is why the idProperty is very useful)
set the record of the fieldset and not the panel
I haven't had the chance to try that, but I'll do it later tonight. But git it a go though.
-- EDIT --
Ok I've finally been abe to code something for you.
A few issues were in your code. I don't really know why you need two stores, but let's say you do. I'm going to give you all the files I used (the two stores, the two models, the three views and the controller). Three main thing were wrong in your code:
you should not load the second store and try to get the record right after. use and 'load' or 'refresh' event for that
SetValues for a form is the correct function to use
You were missing the name property in your form so that the form know to which value of the store/model to bind to the field.
ContactModel:
Ext.define('App.model.Contact', {
extend: 'Ext.data.Model',
config: {
idProperty: 'id',
fields: [
{name: 'id', type: 'int'},
{name: 'name', type: 'string'}
]
}
});
ContactStore:
Ext.define('App.store.ContactStore', {
extend: 'Ext.data.Store',
requires:['App.model.Contact'],
config: {
storeId: 'ContactStore',
model: 'App.model.Contact',
autoLoad :true,
data: [
{id: 0, name: 'Foo'},
{id: 1, name: 'Bar'}
]
}
});
DetailModel:
Ext.define('App.model.Detail', {
extend: 'Ext.data.Model',
config: {
idProperty: 'id',
fields: [
{name: 'id', type: 'int'},
{name: 'name', type: 'string'},
{name: 'billingStreet', type: 'string'},
{name: 'billingCity', type: 'string'}
]
}
});
DetailStore:
Ext.define('App.store.DetailStore', {
extend: 'Ext.data.Store',
config: {
model: 'App.model.Detail',
autoLoad :true,
data: [
{id: 0, name: 'Foo', billingStreet:'here', billingCity: 'Somewhere'},
{id: 1, name: 'Bar', billingStreet:'there', billingCity: 'Somewhere else'}
]
}
});
ContactView:
Ext.define('App.view.ContactList', {
extend: 'Ext.List',
xtype: 'contactList',
fullscreen: true,
config: {
itemId: 'contactList',
store:'ContactStore',
emptyText: 'test',
itemTpl: new Ext.XTemplate(
'{name}'
),
items:[
{
xtype:'toolbar',
docked:'top',
title:'Leeds List'
}
]
}
});
DetailView:
Ext.define('App.view.Detail', {
extend: 'Ext.form.Panel',
requires: ['Ext.form.FieldSet'],
xtype: "detail",
config:{
scrollable:'vertical',
items: [
{
xtype: 'toolbar',
docked: 'top',
title: 'Details'
},
{
xtype: 'fieldset',
itemId: 'detailForm',
items: [{
xtype: 'textfield',
store: 'Details',
name: 'name',
placeHolder : 'Name',
label: 'Name'
},
{
xtype: 'textfield',
store: 'Details',
placeHolder : 'BillingStreet',
name: 'billingStreet',
label: 'BillingStreet'
},
{
xtype: 'textfield',
store: 'Details',
placeHolder : 'BillingCity',
name: 'billingCity',
label: 'BillingCity'
}
]
}
]
}
});
Main view:
Ext.define('App.view.Main', {
extend: 'Ext.Container',
xtype: 'main',
config: {
layout: 'hbox',
items: [
{
xtype: 'contactList',
flex:1
},
{
xtype: 'detail',
flex:2.5
}
]
}
});
Main Controller:
Ext.define('App.controller.Main', {
extend : 'Ext.app.Controller',
requires: [
'Ext.Toolbar',
'Ext.List',
'App.store.ContactStore',
'App.store.DetailStore',
'App.view.Detail',
'App.view.ContactList'
],
config: {
//#private
detailStore: null,
currentListIndex: -1,
views : [
'App.view.ContactList',
'App.view.Detail'
],
refs: {
list: 'contactList',
detail: 'detail',
detailForm: 'detail #detailForm'
},
control: {
list: {
itemtap: 'handleItemTapList'
}
}
},
launch: function() {
var store = Ext.getStore('DetailStore');
store.on('refresh', 'handleDetailStoreLoad', this);
this.setDetailStore(store);
},
handleItemTapList: function(list, index, target, record) {
this.setCurrentListIndex(index);
this.getDetailStore().load();
},
handleDetailStoreLoad: function (store) {
debugger;
var record = store.getAt(this.getCurrentListIndex());
this.getDetail().setValues(record.data);
}
});
We could argue on a few things but I tried to go straight to the point and make it work. If you have more questions please ask but this example is working for me. In my opinion, you might not need the second store, as the contact detail could be nested in the COntact store, and you could use the hasMany property of the store.
use form.setRecord() to load a record into a form
make sure your form elements have name property values that match the model name properties
as you have a store, you will have to get a reference to ONE model to load, using say getAt() or find() methods to get or find a model in your store

Including a data Store makes the app not load

I can't get my application to work using MVC architecture.
Here is the code:
app.js
Ext.application({
name: CONFIG.APP_NS,
appFolder: '../js/app',
autoCreateViewport: true,
/*
models: ['User'],
stores: ['Users'],
//*/
controllers: ['Main', 'Tab', 'Import', 'Export', 'Predict', 'Admin']
});
Import.js (controller)
Ext.define(CONFIG.APP_NS+'.controller.Import', {
extend: 'Ext.app.Controller',
//stores: ['Users'], //Uncommenting this makes the application not load at all
models: ['User'],
views: ['Import.Window', 'Import.Toolbar', 'Import.Grid'],
init: function(){
...
},
...
});
User.js (model)
Ext.define(CONFIG.APP_NS+'.model.User', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'int'},
{name: 'username', type: 'string'},
{name: 'password', type: 'string'},
{name: 'salt', type: 'string'},
{name: 'firstName', type: 'string'},
{name: 'lastName', type: 'string'},
{name: 'email', type: 'string'},
{name: 'admin', type: 'boolean'},
{name: 'authenticated', type: 'boolean'}
],
hasMany: {model: CONFIG.APP_NS+'.model.Roles', name: 'roles'},
proxy: {
type: 'ajax',
url: 'model/users',
reader: {
type: 'json'
}
}
});
Ext.define(CONFIG.APP_NS+'.model.Roles', {
extend: 'Ext.data.Model',
fields: [
{name: 'role', type: 'string'}
],
belongsTo: CONFIG.APP_NS+'.model.User'
});
Users.js (store)
Ext.define(CONFIG.APP_NS+'store.Users', {
extend: 'Ext.data.Store',
requires: CONFIG.APP_NS+'.model.User',
model: CONFIG.APP_NS+'.model.User'
});
Grid.js (view)
Ext.define(CONFIG.APP_NS+'.view.Import.Grid', {
extend: 'Ext.grid.Panel',
alias: 'widget.importgrid',
initComponent: function() {
this.store = Ext.create('Ext.data.Store', { //Works fine with the code as it is
model: CONFIG.APP_NS+'.model.User',
proxy: {
type: 'ajax',
url: 'model/users',
reader: {
type: 'json'
}
}
});
//*/
//this.store = Ext.create(CONFIG.APP_NS+'.store.Users', {});
this.columns = [
{header: 'Name', dataIndex: 'username', flex: 1},
{header: 'Email', dataIndex: 'email', flex: 1}
];
this.callParent(arguments);
this.store.load();
}
});
I have tried almost every combination of stores: in different files possible, nothing seems to do the trick. If I do not include the store anywhere, I get the error Object is not a function (or TypeError: Cannot call method 'on' of undefined if defined outside of the initComponent in the view) somewhere in internal extjs files. It seems that even if I copy the structure from the tutorial examples, it still does not work, so I must be missing something.
What am I doing wrong?
Thank you for your time.
EDITS:
I am running this code on Wamp (localhost). The server has both ExtJS4 and Symfony installed and running.
Updated error message.
Fixed a typo in the Model, see comments.
(I see you have the stores commented out in the app.js. Is this intentional?)
I ran into a similar problem.. as soon as i added the store to my app.js and view.js (a grid panel), my app stopped working.
I'm pretty sure I fixed it by adding the stores (all of them) to the controller and the app.js. Ok.. just checked again, and I get a different error message if the store was missing from controller.js: "Uncaught TypeError: Cannot call method 'on' of undefined" (this is on chrome). Slightly different error message.
Also, consider commenting out the this.store.load().. i.e. remove the server data-access variable - (one thing at a time.)
I found the bug.
Users.js (store)
Ext.define(CONFIG.APP_NS+'store.Users', {
extend: 'Ext.data.Store',
requires: CONFIG.APP_NS+'.model.User',
model: CONFIG.APP_NS+'.model.User'
});
First line should be:
Ext.define(CONFIG.APP_NS+'.store.Users', {
I was missing a period before store.
Molecule Man's comment made me recheck all the definitions, thank you.

Belongs to association in Sencha

How can i fetch a record using belongs to association ?
var Category = Ext.regModel('Category', {
fields: [
{name: 'id', type: 'int'},
{name: 'name', type: 'string'}
]
});
var Product = Ext.regModel('Product', {
fields: [
{name: 'id', type: 'int'},
{name: 'category_id', type: 'int'},
{name: 'name', type: 'string'}
],
associations: [
{type: 'belongsTo', model: 'Category'}
]
});
Amol,
I speak only of ExtJS 4, so if you can relate this to ExtJS 3 then great, but you would retrieve multiple records via a store:
As a starting point though you could do
var records = Ext.StoreManager.lookupStore("productStore").load({
belongTo: 'books',
callback: function(records) {
Ext.each(records,function(record) {
console.log(JSON.stringify(record.raw))
});
}
});
Depending on the proxy setup on the productStore, this will append belongTo to the querystring so if reader proxy has url: /products and the extra params belongTo is sent this will hit the server with /products?belongTo=books

Resources