ExtJS 4 (MVC) Store not using my custom Model class - extjs4

I'm using ExtJS 4.0.7 with its standard MVC architecture. I have a grid with custom store and model classes. The data is loaded remotely via store.load(). I'm using ext-dev.js for debug purposes with dynamic dependency loading.
The app loads fine with no errors in Chrome's console. But the problem is that the records in my store have exactly the same data as provided by my AJAX call, regardless of what fields I have in my model. I even tried renaming and deleting fields but Ext is not paying attention.
Browsing my store object using the console shows that the records all have their own custom runtime-generated model class named Ext.data.reader.Json-Modelext-gen1141. Here is the gist of my code:
My model:
Ext.define('MyApp.model.FooModel', {
extend: 'Ext.data.Model',
idProperty: 'column1',
fields: [
{name: 'column1', convert: function(value, record) {
return value + ' TEST-TEST-TEST';
}},
'column2',
'column3'
]
});
My store:
Ext.define('MyApp.store.FooStore', {
extend: 'Ext.data.Store',
model: 'MyApp.model.FooModel',
autoLoad: false,
proxy: {
type: 'ajax',
url: '/blah/blah',
reader: {
type: 'json'
}
}
});
My grid:
Ext.define('MyApp.view.FooGrid', {
extend: 'Ext.grid.Panel',
alias: 'fooGrid',
store: 'FooStore',
columns: [{
text: 'Column 1',
dataIndex: 'column1',
flex: 1
},{
text: 'Column 2',
dataIndex: 'column2',
flex: 1
},{
text: 'Column 3',
dataIndex: 'column3',
flex: 1
}]
});
My controller:
Ext.define('MyApp.controller.Foo', {
extend: 'Ext.app.Controller',
views: ['FooGridFrame'],
models: ['FooModel'],
stores: ['FooStore'],
init: function() {
this.control({
'fooGrid': {
activate: function(grid) {
grid.getStore().load();
}
}
});
}
});
I can't tell what I'm doing wrong. Any ideas?

It turns out that the AJAX backend (written by another dev for Ext3) was providing some config data via a metaData property. I didn't know that Ext's Store paid any attention to this. My problem was solved by updating the backend to omit the metaData property.
It probably would have also worked to update metaData to provide the appropriate config that I needed, but I'm refactoring to make all the UI config happen in the client.

Related

Sencha Touch synch not saving to proxy

I have a piece of code in a Sencha Touch v2 controller as shown below. When this code is ran the count after the store.add is (6), the counter after the store.sync is (0) and the store.sync is succeeding.
NOTE: items holds 6 records received from a JsonP proxy, no errors are shown in the console and everything acts as though it was a full success.
requires: [
'Ext.data.proxy.JsonP',
'Ext.data.proxy.Sql'
],
config: {
models: ['Convention'],
stores: ['Conventions']
},
// ***additional code*** //
store.setProxy({
type: 'sql',
database: 'app',
table: 'Conventions'
});
store.removeAll();
store.sync({
success: function(batch){
store.add(items);
console.log("Count before: " + store.getCount()); << Shows (6)
store.sync({
failure: function (batch, options) {
console.log('Convention Sql failure');
},
success: function(batch,options){
console.log("Count after: " + store.getCount()); << Shows (0)
console.log("Convention Sql success");
store.load();
Ext.Viewport.unmask();
}
});
}
});
The model is show here
extend: 'Ext.data.Model',
config: {
idProperty: 'id',
fields: [
{ name: 'id', type: 'string' },
{ name: 'name', type: 'string' },
{ name: 'logoId', type: 'string' },
{ name: 'seasonId', type: 'string'},
{ name: 'viewed', type: 'string'},
{ name: 'dateCreated', type: 'string'},
{ name: 'dateUpdated', type: 'string'}
]
}
and the store is here
extend: 'Ext.data.Store',
requires: [
'Ext.data.proxy.Sql'
],
config: {
model: 'app.model.Convention',
autoLoad: false,
sorters:[{
property: 'name',
direction: 'ASC'
}],
proxy: {
type: 'sql',
database: 'app',
table: 'Conventions'
}
}
After much research it seems that Sencha recently changed some of their code on how they handle IDs. As such, if you are using code examples previous to this change you will get errors when you try to save to the ID field.
Sencha has added the clientIdProperty that you can add to the writer of a proxy and directly to the model.
Reference: http://docs.sencha.com/touch/2.4/2.4.2-apidocs/#!/api/Ext.data.Model-cfg-clientIdProperty
The name of a property that is used for submitting this Model's unique client-side identifier to the server when multiple phantom records are saved as part of the same Operation. In such a case, the server response should include the client id for each record so that the server response data can be used to update the client-side records if necessary. This property cannot have the same name as any of this Model's fields.
As such, my code above will have the following changes to the following where 'siteId' is my id being passed from the Json request and the ID on my server for the record.
model
idProperty: 'id',
clientIdProperty: 'siteId',
identifier: 'uuid',
Controller
store.setProxy({
type: 'sql',
database: 'app',
table: 'Conventions',
writer: {
clientIdProperty: 'siteId'
}
});

Calling data from store in a normal Tab Panel

I'm trying to call 2 values from my store, and set it inside the styles in a div which I put it in a html: item. The store loads the data from a web API, which is working fine(I've tested using fiddler and the return response is correct) but I cant get the data in the store to work inside the html item.
Below is my view:
Ext.define('myapp.view.Main', {
extend: 'Ext.tab.Panel',
requires:['myapp.store.Style'],
items: [
{
id: 'firstpage',
title: 'Welcome',
store: 'styleStore',
styleHtmlContent: true,
scrollable: true,
items: [
{
html: ['<div id="testStr1" style="font-style:{FontStyle}; color:{Color};">',
'This is a test string.',
' Go to the settings to change the style',
'</div>'
].join("")
}
]
},
}
]
}
My Store:
Ext.define('myapp.store.Styles', {
extend: 'Ext.data.Store',
requires:[
'myapp.model.Style'
],
config: {
autoLoad: true,
model: 'myapp.model.Style',
storeId: 'styleStore',
clearOnPageLoad:false,
proxy:
{
type: 'ajax',
listeners: {
exception:{
fn: function(pxy, response, operation, options){console.log("We've got a problem...");}
}
},
url: 'http://localhost/styleapi/api/styles',
reader: {
type: 'json',
rootProperty: 'data',
}
}
}
});
My model:
Ext.define('myapp.model.Style', {
extend: 'Ext.data.Model',
fields:[
{
name: 'Id',
type: 'int'
},
{
name: 'FontStyle'
},
{
name: 'Color'
},
],
proxy: {
type: 'rest',
url: 'http://localhost/styleapi/api/styles'
}
});
A few issues here...
First, your main class, myapp.view.Main, is nesting items inside it, and those items are not configured correctly. Your items: ... should be inside of config, and there should be an xtype for each item, if you want the item to not be the default type of container. In your current code, you have an items: .. config on your first item, where you are putting html. This results in a nested component, which is not what you are intending here.
In addition, you are using html, when you really want to use a template. When you have a fixed set (or object) of data, you can use a component with tpl and data; when using a store for the data, you would use a dataview with an itemTpl config, which will repeat that template for each item in the store. Currently, your top-level item is defaulting to a container, where you are using a store config, which won't do anything at the moment.
So, steps to fix:
Move the top-level item into config property
Change the top-level item to be a dataview
Move the html out of the nested item and into an itemTpl property as an XTemplate (i.e. itemTpl: new Ext.XTemplate('<div ...'))

Populate custom component with store

Im trying to populate a custom component using a store (actually a store with local data) in a Sencha Touch 2 project.
My idea is to create one custom component for each element in the store, but actually nothing happens.
I have tried several things but anything works, could you help me? I have done an example to show the problem:
model:
Ext.define('project.model.city', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'country', type: 'string'},
{name: 'city', type: 'string'}
]
}
});
store:
Ext.define('project.store.cities', {
extend: 'Ext.data.Store',
requires: ['project.model.city'],
model: 'project.model.city',
autoLoad: true,
data: [
{ country: 'Germany', city: 'Berlin' },
{ country: 'Italy', city: 'Rome' }
]
});
View with store:
Ext.define('project.view.cityAll', {
extend: 'Ext.Panel',
xtype: 'cityAllView',
config: {
items:[{
xtype: 'cityItemView',
store: 'project.store.cities',
}]
}
});
Custom component View:
Ext.define('project.view.cityItem', {
extend: 'Ext.Panel',
xtype: 'cityItemView',
config: {
items: [{
itemTpl: '{city}'
}]
}
});
You need to assign store to cityItemView instead of cityAllView. cityItemView is having template specified and needs to be loaded with data.
Ext.define('project.view.cityItem', {
extend: 'Ext.Panel',
xtype: 'cityItemView',
config: {
items: [{
xtype:'list',
itemTpl: '{city}'
store:'project.store.cities'
}]
}
});
If you want to set data into panel, then you'd need to call setData(). A panel can not load data from store directly. You can use list view instead so show city, country pair. cityView no longer needed store property that way.
Give this a try.
You can add load listener in store which would loop through records and create as many panels:
listeners : {
load: function( me, records, successful, operation, eOpts ){
var plist = [];
var cv = Ext.Create('project.view.cityAll');
if(successful){
var data = records[i].getData();
for(var i=0; i<records.length; i++){
plist.push({
xtype : 'cityItemView',
data : data
});
}
cv.add(plist);
}
// Now add cv to viewport or wherever you want
}
}
You have to change cityItemView to use data whichever way you want. If you are using initialize method you can access it like this.config.data

Saving Model with hasOne association

I've got these models :
Ext.define('TestApp.model.User', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'username', type: 'string'},
],
proxy: {
type: 'localstorage',
},
},
});
Ext.define('TestApp.model.Config', {
extend: 'Ext.data.Model',
config: {
hasOne : {model: 'TestApp.model.User', name: 'user'},
proxy: {
type: 'localstorage',
},
}
});
I've tried to save a config entry like this :
var david = Ext.create('TestApp.model.User', {username: 'david'})
david.save();
var config = Ext.create('TestApp.model.Config');
config.setUser(david);
config.save();
When I restart the application, I have my user entry saved and my config entry saved but, my association is not saved:
config.getUser() -> I get undefined
According to Mitchell Simoens storing associated data isn't supported.
Unsure if it helps in your case, but an approach is sketched (that approach also seems to adress my own current (unrelated) problem).
Hope it helps

Extjs4 -how to generate the grid from the returned json?

I have a form and a grid to submit a query,like this:
items:[
{
fieldLabel: 'query the month',
xtype : 'textfield',
name : 'query_year_month',
id: 'query_year_month'
} ],
buttons: {
text: 'submit',
formBind: true, //only enabled once the form is valid
disabled: false,
handler: function() {
//some code
}
var store = Ext.create('Ext.data.Store', {
model: //uncertain,
region : 'south',
pageSize: 15,
proxy: {
type: 'ajax',
url : 'brokee/brokagequery/',
reader: {
type: 'json',
root: 'users'
}
},
autoLoad: false
});
I'd like to load data to a grid after submiting the form.The return data is a json
structure,I don't want to define the static model bind to the store and neither the grid columns,because the data returned is uncertained. The store model and grid columns should be generated from the json data,
for example: json: {'field1':data1, 'field2':data2}
the model should be generated like this:
Ext.define('somemodel', {
extend: 'Ext.data.Model',
fields: [
{name: 'field1', type: 'string'},
{name: 'field2', type: 'string'}
]
});
In the official demo, the store and model are predefined, then call the store.load method to refresh the grid throuth the proxy.But how can I do that when the store and model need to be generated?
When you have your json loaded, you can create store store/model like this.... use record .raw to extract values and :
Ext.create("Ext.data.JsonStore",{
id:record.raw.storeID,
model: Ext.define('App.dataGridModel', {
extend: 'Ext.data.Model',
fields: [record.raw.id, record.raw.first]...
})
...
});
the same with the grid etc..