I have a JSON response like this
"{"total":1,"userBeanId":300,"list":[{"errors":[],"success":true,"liferayUserId":31503,"companyId":null,"groupId":null,"locale":null,"status":null,"liferayUserGroupId":null,"idProvider":null,"idClient":null,"userType":4,"userId":200,"email":"xpto#gmail.com","telefone":"999999999","nome":"MYNAME","role":"MY_ROLE","perfil":"Administrator","lastName":null}],"success":true}"
and what I have is a store that reads the list content, like this
"Ext.define('
MYPROJECT.store.Profiles', {
extend: 'Ext.data.Store',
model: 'MYPROJECT.model.Profile',
autoLoad: true,
pageSize: 10,
remoteSort: true,
remoteFilter: true,
proxy: {
type: 'ajax',
api: {
read: '/delegate/rlapi-common/profile/list'
},
enablePaging: true,
reader: {
type: 'json',
root: 'list',
successProperty: 'success'
}
}
});"
and the store "reads" the list successfully. However, I'd like to be able to access the "userBeanId" field as well. Is there any way I can access it by this store (by changing the root to something on an upper-level)? It confuses me as the store "maps" to a model and the userBeanId doesn't fit in the model.
Model:
Ext.define('MYPROJECT.model.Profile', {
extend: 'Ext.data.Model',
fields: [
'userId',
'nome',
'telefone',
'email',
'role',
'perfil'
],
});
You can access store.proxy.reader.rawData to get the most recently loaded JSON. As you suggested, it doesn't make sense being part of the model, but you can read extra meta info via the reader.
Related
I want to implement dynamic grid in Extjs. I have found this How do you create table columns and fields from json? (Dynamic Grid) and the accepted answer looks good.
In my case I have no proxy store but a proxy model:
fields: [ {name: 'id', type: 'int', persist: false},
{name: 'gender', type: 'auto'},
{name: 'name', type: 'auto'},
{name: 'age', type: 'int'}],
identifier: 'sequential', // to generate -1, -2 etc on the client
proxy: {
type: 'rest',
idParam: "id",
url:'http://localhost:3000/posts',
api:
{
read : 'http://localhost:3000/db',
create: 'http://localhost:3000/posts',
update : 'http://localhost:3000/posts' ,
destroy : 'http://localhost:3000/posts'
},
headers: {'Content-Type': "application/json" },
reader: {
type: 'json',
rootProperty:'posts',
totalProperty: 'total'
},
writer: {
type: 'json'
}
My store looks like is:
model: 'ThemeApp.model.peopleModel',
storeId: 'peopleStore',
pageSize: 500,
autoLoad: true,
autoSync: true,
pageSize: 5,
autoLoad: {start: 0, limit: 5},
autoSync: true,
sorters: [{
property : 'age',
direction:'ASC'
}],
groupField: 'gender'
});
In my view I have defined columns:[] But I don't know where to call metachange function.
Can anyone tell me where to use metachange function and should I use metachange function of store or proxy?
Generally you don't want to configure proxy on the model, that is only useful when you want to use standalone Model instances without a store.
Move the proxy config to the Store, and make the server respond to read requests with additional metadata object, which you can then use in the metachange event handler to configure the grid.
Using Reader metadata is the right way to do "dynamic" Grids.
I use ExtJS 4.2.2. A store for browsing and managing folders is defined like this:
Ext.define('hds.store.CaseFolders', {
extend: 'Ext.data.Store',
requires: [
'app.model.Folder',
'Ext.data.proxy.Rest',
'Ext.data.reader.Json',
'Ext.data.writer.Json'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: false,
model: 'app.model.Folder',
storeId: 'Folders',
proxy: {
type: 'rest',
url: '/api/folders.json',
reader: {
type: 'json',
messageProperty: 'message',
root: 'data'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
}
}
}, cfg)]);
}
});
It uses this model:
Ext.define('app.model.Folder', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.Field'
],
fields: [
{
name: 'name',
type: 'string'
},
{
name: 'parentId',
type: 'int'
},
{
name: 'type',
type: 'string'
}
]
});
Folders can be added, renamed and removed.
When changing the name of the folder, for example and using store.sync(), the record is properly synced to the server with a PUT containing id and name attributes.
However, when deleting the folder, store.sync() doesn't send any request to the server. A callback function was added to sync, but it is not called at all.
It seems that the REST store (proxy?) "thinks" that there is nothing to sync to the server.
Why is it like that?
Found the reason for the problem that I had:
The store is filtered to show content of the folder to be deleted.
When wanting to delete current folder, its record is filtered away.
Adding a line to remove filters before removing the parent folder record solved the problem.
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.
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'm using ExtJS v4 for making some rich interfaces, the problem is that i encounter difficulties from time to time (something quite normal for a beginner in Extjs: p), the problem i encounter now, concern the pagination, in fact on my page i have all the records that are displayed, even after specifying the item by nbr of pages if possible to help me thanks
Ext.onReady(onReady);
function onReady() {
var itemsPerPage = 10;
var store = new Ext.data.JsonStore({
autoLoad: false,
pageSize: itemsPerPage,
proxy: new Ext.data.HttpProxy({
type: 'ajax',
url: '../Service.asmx/GetMyDvpt',
reader: {
type: 'json',
root: 'd',
//totalProperty: 'total',
idProperty: 'Id'
},
headers: {
'Content-type': 'application/json'
}
}),
fields: ['NOM_EXP', 'NOM_ESP', 'NOM_VAR', 'SURF_PG', 'DD_CYCLE_PROD']
});
store.load({
params: {
start: 0,
limit: itemsPerPage
}
});
Ext.create('Ext.grid.Panel', {
store: store,
columns: [
{ dataIndex: 'NOM_EXP', header: 'NOM_EXP' },
{ dataIndex: 'NOM_ESP', header: 'NOM_ESP' },
{ dataIndex: 'NOM_VAR', header: 'NOM_VAR' },
{ dataIndex: 'SURF_PG', header: 'SURF_PG' },
{ dataIndex: 'DD_CYCLE_PROD', header: 'DD_CYCLE_PROD', flex: 1 }
],
renderTo: 'panel',
title: 'Dvpt Grid',
width: 570,
height: 350,
dockedItems: [{
xtype: 'pagingtoolbar',
store: store,
dock: 'bottom',
displayInfo: true
}]
});
}
You must create new instances of Ext JS objects with Ext.create, because objects instantiated with the new keyword won't take care of the Ext JS class system.
When you look at the load() method source code, you'll see how the configuration options get applied, and so would you:
store.load({
start: 0,
limit: itemsPerPage
});
Since the store has already been configured with pageSize, there's no need for the limit options, since it gets the pageSize as default.
store.load({
start: 0
});
I'd also recommend to have a look at the loadPage() method, that handles setting all the paging relevant parameters correctly:
store.loadPage(1);
Another enhancement is to set autoLoad to true, then you could omit the store load completely.
There is also no need to create a Ext.data.HttpProxy manually, since the configuration object specifies the ajax type and will take care of instantiating the correct proxy type for you.
Since you specified a JSON reader, there should be no need to set the HTTP accept header. Content-Type is anyway a response header and the corresponding request header would be Accept.
So your code should look like this:
Ext.onReady(onReady);
function onReady() {
var store = Ext.create('Ext.data.JsonStore', {
autoLoad: true,
pageSize: 10,
proxy: {
type: 'ajax',
url: '../Service.asmx/GetMyDvpt',
reader: {
type: 'json',
root: 'd',
totalProperty: 'total',
idProperty: 'Id'
}
},
fields: ['NOM_EXP', 'NOM_ESP', 'NOM_VAR', 'SURF_PG', 'DD_CYCLE_PROD']
});
Ext.create('Ext.grid.Panel', {
store: store,
columns: [
{ dataIndex: 'NOM_EXP', header: 'NOM_EXP' },
{ dataIndex: 'NOM_ESP', header: 'NOM_ESP' },
{ dataIndex: 'NOM_VAR', header: 'NOM_VAR' },
{ dataIndex: 'SURF_PG', header: 'SURF_PG' },
{ dataIndex: 'DD_CYCLE_PROD', header: 'DD_CYCLE_PROD', flex: 1 }
],
renderTo: 'panel',
title: 'Dvpt Grid',
width: 570,
height: 350,
dockedItems: [{
xtype: 'pagingtoolbar',
store: store,
dock: 'bottom',
displayInfo: true
}]
});
}
When dealing with problems like this, I usually test the backend service with a REST client. There are many addons for different browsers available, for example RESTClient for Firefox or Advanced REST clinet for Chrome. Make sure that your service behaves correct without any UI, just by sending plain HTTP request with manually defined parameters. Only move to the GUI part when when everything works as expected.
For the GUI part I encourage you to study the source code of Ext JS within the API Documentation, it's well structured and documented and you'll learn a lot.
Since version 4 Ext JS comes with a MVC application framework, which simplifies the creation of large RIA apps a lot. Read more at the Application Architecure Guide.
Paging Toolbar supports remote paging by default. If local paging is required paging then reload store on 'datachange' and 'refresh' event fired.