I've got a Json file......
[
{
"Title":"Package1",
"id":"1",
"POI":[
{
"Title":"POI1",
"LayerID":"1",
},
{
"Title":"POI2",
"LayerID":"1",
}
},
{
"Title":"Package2",
"id":"2",
"POI":[
{
"Title":"POI3",
"LayerID":"2",
},
{
"Title":"POI4",
"LayerID":"2",
}
}
]
populating a store.....
Ext.define('Murmuration.store.MyPackages', {
extend: 'Ext.data.Store',
xtype: 'myPackages',
config: {
model: 'Murmuration.model.PackagesModel',
proxy: {
type: 'ajax',
url : 'data/store.json',
reader: {
type: 'json'
}
},
autoLoad: true
}
});
with a model......
Ext.define('Murmuration.model.PackagesModel', {
extend: 'Ext.data.Model',
xtype: 'packagesModel',
config: {
fields: [
{name: 'Title', type: 'string'},
{name: 'id', type: 'int'}
]
}
});
for said list......
Ext.define('Murmuration.view.homeList', {
extend: 'Ext.List',
xtype: 'homeList',
fulscreen: true,
config: {
title:'Murmuration',
itemTpl: '<div>{Title}</div>',
store:'MyPackages',
fulscreen: true,
}
});
The list Items are successfully being populated with 'Package1' and 'Package2'. But for the life of me I can't successfully change the code to populate the list with the POI titles for the fist package........'POI1' and 'POI2'. How would I go about successfully implementing the following? Any help would be greatly appreciated.
The json you've given is nested so things little different here. First thing is, you need to specify a rootProperty in your reader. So you define a root element in your json and that element will be set to rootProperty.
Next part is, you have POI as array of objects. So you'd need a separate model for POI.
Model for POI can be defined -
Ext.define('Murmuration.model.POIModel',{
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'Title', type: 'string'},
{name: 'LayerID', type: 'int'}
],
belongsTo:'Murmuration.model.PackagesModel'
}
});
After a close look, you'll notice there's one extra config belongsTo. This represents many to one association with your PackageModel since there are many POI in each package.
After doing this, you'd need to change you PackageModel also to -
Ext.define('Murmuration.model.PackagesModel', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'Title', type: 'string'},
{name: 'id', type: 'int'}
]
},
hasMany:{
associationKey:'POI',
model:'Murmuration.model.POIModel',
name:'POI'
}
});
here, hasMany represents that this model is having multiple model instances of POI model. associationKey is the key POI from you json and model gives the model instance of POI model.
After doing that you'd need to change your reader in store to -
Ext.define('Murmuration.store.MyPackages', {
extend: 'Ext.data.Store',
config: {
model: 'Murmuration.model.PackagesModel',
proxy: {
type: 'ajax',
url : 'data/store.json',
reader: {
type: 'json',
rootProperty:'items'
}
},
autoLoad: true
}
});
rootProperty should be set to root of you json. I assumed it could be items here.
Finally in you view you can have template set up like this -
itemTpl: new Ext.XTemplate(['<div>Package Title => {Title}'+
'<tpl for="POI"><h6>POI title => {Title}</h6><h6>POI layer => {LayerID}</h6></tpl></div>'
]),
2 things I found in your code are not correct though -
Store and Model can not have a xtype.
All the config options should be inside config:{} only.
Related
I have a simple model, let's say:
Ext.define('UserModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'firstname', type: 'string'},
{name: 'lastname', type: 'string'}
]
});
And a json file that looks like this:
{
"DatabaseInJSON": {
"Users": [
{
"KeyFirstName": "John",
"KeyLastName": "Doe"
},{
"KeyFirstName": "James",
"KeyLastName": "Howlett"
}
],
"OtherStuffWeDontCareAbout": [
...
]
}
}
My question is:
If I create a store like this, how can i map the attribute "firstname" from my model to "KeyFirstName" from my json ?
Ext.define('my.custom.Store', {
extend: 'Ext.data.Store',
model: 'UserModel',
proxy: {
type: 'ajax',
url: 'path/to/my/file.json',
reader: {
type: 'json',
rootProperty: 'DatabaseInJSON'
}
}
});
You need to either employ mapping or a convert function
Have a look at the demo here which demonstrates both in action.
For the sake of the demo I turned your store into a memory proxy store and you are I presume also accessing your rootProperty wrong as it should be rootProperty: 'DatabaseInJSON.Users'
Code:
Ext.application({
name: 'Fiddle',
launch: function() {
myData = {
"DatabaseInJSON": {
"Users": [{
"KeyFirstName": "John",
"KeyLastName": "Doe"
}, {
"KeyFirstName": "James",
"KeyLastName": "Howlett"
}],
"OtherStuffWeDontCareAbout": {}
}
};
Ext.define('UserModel', {
extend: 'Ext.data.Model',
fields: [{
name: 'firstname',
mapping: 'KeyFirstName',
type: 'string'
}, {
name: 'lastname',
convert: function(v, record) {
return record.data.KeyLastName;
},
type: 'string'
}]
});
Ext.define('my.custom.Store', {
extend: 'Ext.data.Store',
model: 'UserModel',
proxy: {
type: 'memory',
reader: {
type: 'json',
rootProperty: 'DatabaseInJSON.Users'
}
}
});
myStore = Ext.create('my.custom.Store', {
data: myData
});
console.log(myStore.getRange());
}
});
Generally your Json properties should match the same names of your fields so that the reader can read them properly, to map 'KeyFirstName' to 'firstname' I think your best option would be to create a mapping in the field definition on the model.
This would apply this globally for all requests and I believe it would reverse the mapping when it come to saving the data.
To use the mapping in your case, you would need something like:
Ext.define('UserModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'firstname', type: 'string', mapping: function(data) { return data.KeyFirstName; } },
{name: 'lastname', type: 'string', mapping: function(data) { return data.KeyLastName; } }
]
});
Other than changing the format of the JSON data, the only other way I can think of would be to override the read or getResponseData method of the JsonReader
I receive an array of strings from the server.
How can I populate my grid panel if the data is not in key-value format?
Here is the response:
{"result":true,"data":["dep1","dep2","dep3"],"totalCount":3}
Here is my grid panel
xtype: 'gridpanel',
flex: 1,
itemId: 'departmentsGridPanel',
title: '',
store: new Ext.data.ArrayStore({
autoLoad: true,
fields: [
'department'
],
proxy: {
type: 'ajax',
url: 'FilteringDataServlet?filterColumn=avdeling',
reader: {
type: 'json',
root: 'data'
}
}
}),
columns: [{
text: 'Avdeling',
flex: 1,
dataIndex: 'department'
}],
Then you should use Ext.data.reader.Array with mapping parameter.
Employee = Ext.define('Employee', {
extend: 'Ext.data.Model',
fields: [
{name: 'name', mapping: 0}, // "mapping" only needed if an "id" field is present which
{name: 'occupation', mapping: 1} // precludes using the ordinal position as the index.
]
});
I have solved this by adding load listener to my store and modifying the data there
listeners: {
load: function(store, records, success, opts) {
store.each(function(record) {
record.set('department', record.raw);
});
}
}
I have tried to create a new empty record without creating a model.
Accidentally I tried to run this:
new new storeComp.model()
and it actually works!
anyone know any solution for this or an answer to how is it working ?
Thanks!
Shalev
Stores that are not configured with a model will create an anonymous one implicitly. This is explained in the docs for the implicitModel private property (the store needs to know that because if it uses an implicit model, it must destroy it when it is itself destroyed).
In the end that means that you can safely expect any store to be backed with a model.
I faced the same problem for an associative store. For that i have used below JSON format to load project store. So automatically empty record is created in associative (project-resources) Store.
Store:
Ext.define('App.store.Projects', {
extend : 'Ext.data.Store',
model : 'App.model.Project'
});
Models:
Ext.define("App.model.Project", {
extend: 'Ext.data.Model',
idProperty : 'id',
uses : ['App.model.ProjectResource'],
fields: [
{ type: 'auto', name: 'id'},
{ type: 'number', name: 'customerid'},
{ type: 'string', name: 'projectcode'}
],
associations: [
{type: 'hasMany', model: 'App.model.ProjectResource', name: 'Resources', storeConfig: { remoteFilter: true }}
]
});
Ext.define("App.model.ProjectResource", {
extend: 'Ext.data.Model',
idProperty : 'id',
fields: [
{ type: 'number', name: 'id'},
{ type: 'string', name: 'name'},
{ type: 'number', name: 'projectid'},
{ type: 'auto', name: 'resourceid'}
],
associations : [
{type : 'belongsTo', model: 'App.model.Project'}
]
});
JSON Format:
[
{
"id": "105",
"customerid": "105",
"projectcode": "ALN01",
"Resources": {}
}
]
Loading store with empty object (like "Resources": {}) will create empty model.
This topic has been discussed several times on the web but all subjects none helped me solve my problem.
My javascript code receives the JSON nested data. All JSON data Level 1 data are transcribed in the grid panel but all child data none.
I have tried so many ways but impossible.
That's why I'm asking you to help me please.
My JSON:
{
"success":true,
"error":false,
"redirectUrl":null,
"fund":[{
"cat_id":1,
"catname":"Europe OE Japan Large-Cap Equity",
"region":{
"region_id":2,
"region_name":"JAPAN"
}
},{
"cat_id":2,
"catname":"Europe OE Europe Large-Cap Growth Equity",
"region":{
"region_id":1,
"region_name":"EUROPE"
}
}]
}
MY model:
var Recommended = new function() {
this.DataModel = function() {
Ext.define('Fund', {
extend: 'Ext.data.Model',
fields: [{
name: 'catname',
type: 'string'
},{
name: 'cat_id',
type: 'int'
}],
proxy :{
type: 'rest',
url: application +'directory/function',
reader: {
type: 'json',
root: 'fund'
}
},
associations: [{
type: 'hasOne',
model: 'Region',
primaryKey: 'region_id',
name:'region'
}]
});
Ext.define('Region', {
extend: 'Ext.data.Model',
fields: [{
name: 'region_name',
type: 'string'
},{
name: 'region_id',
type: 'int'
}]
});
}
My Store & grid Panel:
this.JSONstore = function() {
var storeRecommended;
storeRecommended = Ext.create('Ext.data.Store', {
model: 'Fund',
autoLoad:true,
groupField: 'region_name'
});
var colModel =
[
{
text: 'REGION',
width: 200,
dataIndex: 'region_name',
name:'region_name',
mapping:'region.region_name'
},{
text: 'MORNINGSTAR',
width: 300,
dataIndex: 'catname',
name:'catname'
}
];
var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
groupHeaderTpl: 'Classe: {name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})',
hideGroupedHeader: false
});
var grid = Ext.create('Ext.grid.Panel', {
renderTo: 'recommendedlists',
collapsible: true,
iconCls: 'icon-grid',
frame: true,
store: storeRecommended,
width: 1200,
height: 400,
title: 'Test',
resizable: true,
features: [groupingFeature],
columns: colModel,
fbar : ['->', {
text:'Clear Grouping',
iconCls: 'icon-clear-group',
handler : function(){
groupingFeature.disable();
}
}]
});
}
this.initControlsOnload = function() {
Recommended.DataModel();
Recommended.JSONstore();
}
} // close Recommended function
The problem is your store bound to the grid knows nothing about Regions. It stores Funds. So you can't ask for a column to map to a data property that's not in the store.
The store is flat list of Fund records. And sure an individual Fund itself might know about the Region it belongs to, but the store containing a list of funds does not.
What to do?
What needs to happen is flattening out of your data structure on the client side. Why? Because the grid is flat. If you had multiple regions per fund - then we would be talking about a different solution.
How to do that?
If you control the server side of this app then add a Region field to the Fund object, then your data set is simple, straight forward and more importantly flat. If you can't (or don't want to) change the server side, then you can change the client side Model mapping. Essentially you would change your Fund model to something like this:
Ext.define('Fund', {
extend: 'Ext.data.Model',
fields: [
{ name: 'catname', type: 'string' },
{ name: 'cat_id', type: 'int' },
{ name: 'region_name', type: 'string',
mapping: 'region.region_name'},
{ name: 'region_id', type: 'int',
mapping: 'region.region_id'}
]
....
});
You see what we did there? We flattened the Region data into the Fund record. And now your store will have no problems accessing Region name data by name.
Good Luck,
Dmitry.
I've been trying to figure this out all evening but to no avail. I have a JSON structure as follows (coming from another system so I can't change its structure):
{
"parents":{
"parent":[
{
"parentId":1,
"children":{
"child":[
{
"childId":1,
},
{
"childId":2,
}
]
}
},
{
"parentId":2,
"children":{
"child":[
{
"childId":1,
},
{
"childId":2,
}
]
}
}
],
"pageNum":1,
"pageSize":2
}
}
However, I can't figure out what the correct structure for the data models should be. I've tried the following but it does not work. BTW, I can access the parent information. The issue is with accessing the child information. So, I guess there is something wrong with how I've set up the relationship data.
Ext.regModel("ParentModel", {
hasMany: {
model: 'ChildrenModel',
name: 'children.child' // not too sure about this bit
},
fields: [
{name: 'parentId', type: 'string'}
],
proxy: {
type: 'ajax',
url : 'models.json',
reader: {
type: 'json',
root: 'parents.parent' // this works fine
}
}
});
Ext.regModel('ChildrenModel', {
belongsTo: 'ParentModel', // not too sure about this bit
fields: [{name: 'childId', type: 'string'}]
});
with a data store:
Ext.regStore('ParentModelStore', {
model: 'ParentModel',
autoLoad:true
});
I'm using the following template which gets me the parent information, but I can't get the child data from it:
myapp.views.ParentView = Ext.extend(Ext.Panel, {
layout: 'card',
initComponent: function() {
this.list = new Ext.List({
itemTpl: new Ext.XTemplate(
'<tpl for=".">',
'<div>',
'{parentId}', // this works fine
'</div>',
'<tpl for="children.child">', // this doesn't work
{childId}
'</tpl>',
'</tpl>',
),
store: 'ParentStore',
});
this.listpanel = new Ext.Panel({
layout: 'fit',
items: this.list,
});
this.items = this.listpanel;
myapp.views.ParentView.superclass.initComponent.apply(this, arguments);
},
});
Ext.reg('ParentView', myapp.views.ParentView);
What I'm struggling with is the fact that both the "child" and "parent" elements are surrounded by another element, "children" and "parents" respectively.
Any help much appreciated.
Thanks in advance,
Philip
PS If I remove the outer "children" wrapping element and just leave the inner "child" element (and change "children.child" to "child" in the model definition) the code works fine.
PPS I'm answering my own question:
Doh! I forgot to add the "children" element to the ParentModel's fields.
It should be as follows (note: I didn't need to specify the 'hasMany' or 'associations' elements - not too sure why this is or what is the benefit of including them):
Ext.regModel("ParentModel", {
fields: [
{name: 'parentId', type: 'string'},
{name: 'children'} // VERY IMPORTANT TO ADD THIS FIELD
],
proxy: {
type: 'ajax',
url : 'models.json',
reader: {
type: 'json',
root: 'parents.parent' // this works fine
}
}
});
Ext.regModel('ChildrenModel', {
fields: [{name: 'childId', type: 'string'}]
});
The template works fine too:
'<tpl for="children.child">', // this syntax works too.
{childId}
'</tpl>',
Ran into a similar problem recently..I think.
You need to specify the mapping to the data you want in your model.
For example :
Ext.regModel('Album', {
fields: [
{name: 'artist_name', mapping: 'album.artist.name'},
{name: 'artist_token', mapping: 'album.artist.token'},
{name: 'album_name', mapping: 'album.name'},
{name: 'token', mapping: 'album.token'},
{name: 'small_cover_url', mapping: 'album.covers.s'},
{name: 'large_cover_url', mapping: 'album.covers.l'}
]/*,
getGroupString : function(record) {
return record.get('artist.name')[0];
},*/
});
consumes this JSON:
{
"album":{
"covers":{
"l":"http://media.audiobox.fm/images/albums/V3eQTPoJ/l.jpg?1318110127",
"m":"http://media.audiobox.fm/images/albums/V3eQTPoJ/m.jpg?1318110127",
"s":"http://media.audiobox.fm/images/albums/V3eQTPoJ/s.jpg?1318110127"
},
"artist":{
"name":"New Order",
"token":"OyOZqwkN"
},
"name":"(The Best Of)",
"token":"V3eQTPoJ"
}
},
I've added a converter to allow the template access the data in the model consistently regardless if a single object or an array is returned.
Ext.regModel("ParentModel", {
fields: [
{name: 'parentId', type: 'string'},
{name: 'children', convert:
function(value, record) {
if (value.child) {
if (value.child instanceof Array) {
return value.child;
} else {
return [value.child]; // Convert to an Array
}
}
return value.child;
}
}
],
proxy: {
type: 'ajax',
url : 'models.json',
reader: {
type: 'json',
root: 'parents.parent' // this works fine
}
}
});
Note: I don't actually need to define the ChildrenModel. I guess I can get away without defining it as Sencha must be automatically type converting it.