Retrieving nested JSON data - Ext JS - json

Let's start off with my store:
var newstore = Ext.create('Ext.data.Store', {
fields: ['id', 'table_name', 'name', 'description']
proxy: {
type: 'memory'
}
});
I have some example data here, which comes from a dynamic json response:
{
"elements":[
{
"element":{
"name":"Element Name", <---- This is the value I need**
"id":"Element ID",
"attributes":[
{
"attrname":"id",
"attrvalue":"This is the ID"
},
{
"attrname":"name",
"attrvalue":"This is the name"
},
{
"attrname":"description",
"attrvalue":"This is the description"
},
{
"attrname":"table_name",
"attrvalue":"This is the table"
}
]
}
}
}
And I decode my json here, which places it neatly into my store:
for( var i=0; i < decoded.elements.length; i++ ) {
var element = decoded.elements[ i ].element;
var element_name = element.name; <---- THIS retrieves that value I need
var model = {};
// loop over attributes
for( var x=0; x < element.attributes.length; x++ ) {
var attribute = element.attributes[ x ];
model[ attribute.attrname ] = attribute.attrvalue;
}
// implicitly cast data as Model
newstore.add( model );
}
And lastly, my grid - ResponseList.js:
var grid = Ext.define('MyApp.view.ResponseList' ,{
initComponent: function(columns) {
//config
this.columns = [
{header: 'Element Name', dataIndex: 'What goes here ???'},
{header: 'ID', dataIndex: 'id'},
{header: 'View Name', dataIndex: 'name'},
{header: 'Description', dataIndex: 'description'},
{header: 'Table Name', dataIndex: 'table_name'},
etc...
My question is, how do I place that first name value, Element Name into the first row of my grid? The name name is already taken for the attributes.attrname field, so I'm not sure how to proceed. Everything except Element Name displays just fine.
[Edit]: This is how I want my grid to look:
Any help is appreciated thanks!

In your fields in the store or in a model you can specify mapping which allows for nested json data:
var model = Ext.define('myModel', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
mapping: 'element.id',
type: 'auto'
}],
proxy: {
type: 'ajax',
url: 'data.json',
reader: {
type: 'json',
root: 'elements',
successProperty: ''
}
}
});
var store = Ext.create('Ext.data.Store', {
model: model,
autoLoad: true,
listeners: {
load: function() {
console.log(store);
}
}
});
var grid = Ext.create('Ext.grid.Panel', {
renderTo:Ext.getBody(),
store:store,
columns: {
defaults: {},
items: [{
header: "Id",
dataIndex: "id",
hidden: false
}]
}
});
Here is a fiddle demonstrating working code.

You can probably use the renderer on the grid to get the value you actually need.
{header: 'Element Name', dataIndex: 'What goes here ???',
renderer: function(value, metaData, record, row, col, store, gridView){
return record.someAttribute;
}
},
I'm not sure of the structure of your record, but I think you can guess how to go on from here.
Also, I don't think all that manual decoding is necessary, I can't figure out how you want your grid to look, but if you post a sketch of it or something maybe we can make all that decoding look cleaner.

Related

Extjs 5 add filters to grid dynamically on reconfigure

I have a grid that is generated dynamically
I build the columns array and store, then call reconfigure on my grid
Next I create a filter array. Now filters have to be applied to the columns in my grid.
But the filters are not reflected in my grid. How can ths be achieved?
myView.js
Ext.define('myView.view.myView', {
extend: 'Ext.grid.Panel',
plugins: 'gridfilters',
store: 'myStore.store.myStore',
pageSize:10,
dockedItems: [{
xtype: 'pagingtoolbar',
store: 'WhiskerPlot.store.settingStore', // same store GridPanel is using
dock: 'bottom',
displayInfo: true
}],
filters :[]
});
myController.js
var colFilters = [];
colFilters.push({
type : 'list',
dataIndex : dummyDataIndex,
options : [small,large]
});
var filters = {
ftype : 'filters',
filters : colFilters
};
var gridview = Ext.ComponentQuery.query('myView')[0];
gridview.reconfigure(store,columnarr);
gridview.filters.addFilters(filters);
Add the filters to the column array itself.
Copied from: Filters Doc
var grid = Ext.create('Ext.grid.Panel', {
store: {
url: 'path/to/data'
},
plugins: 'gridfilters',
columns: [{
dataIndex: 'id',
text: 'Id',
filter: 'number'
}, {
dataIndex: 'name'
text: 'Name',
filter: {
type: 'string',
value: 'Ben'
}
}, {
...
}]
});

Extjs MVC run function after store loads

I've got a grid getting data through a json store. I want to display the total number of rows in the grid. The problem is that the store.count() function is running before the store loads so it is returning 0. How can I get my count function to run only once the store has loaded? I'm working in MVC, here is my app.js which has my counting logic in it.
Thank you for any help
Ext.application({
name: 'AM',
appFolder: 'app',
controllers: [
'Users'
],
launch: function(){
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider'));
Ext.create('Ext.container.Viewport', {
resizable: 'true',
forceFit: 'true',
layout: 'fit',
items:[{
xtype: 'userpanel',
}]
});
var port = Ext.ComponentQuery.query('viewport')[0],
panel = port.down('userpanel'),
grid = panel.down('userlist'),
label = panel.down('label');
var count = grid.store.getCount();
var labelText = "Number of people in list: " + count;
label.setText(labelText);
}
});
store code:
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
model: 'AM.model.User',
autoLoad: true,
autoSync: true,
purgePageCount: 0,
proxy: {
type: 'rest',
url: 'json.php',
reader: {
type: 'json',
root: 'queue',
successProperty: 'success'
}
},
sortOnLoad: true,
//autoLoad: true,
sorters: [
{
property: 'PreReq',
direction: 'DESC'
},
{
property: 'Major1',
direction: 'ASC'
},
{
property: 'UnitsCompleted',
direction: 'DESC'
}
],
listeners:{
onload: function(){
var port = button.up('viewport'),
grid = port.down('userlist'),
panel = port.down('userpanel'),
label = panel.down('label'),
count = grid.store.getCount(),
labelText = "Number of people in list: " + count;
label.setText(labelText);
},
scope: this
}
});
grid code:
Ext.define('AM.view.user.List' , {
extend: 'Ext.grid.Panel',
alias: 'widget.userlist',
store: 'Users',
height: 'auto',
width: 'auto',
//resizable: 'true',
features:[{
ftype: 'grouping'
}],
autoFill: 'true',
layout: 'fit',
autoScroll: 'true',
initComponent: function() {
function renderTip(value, metaData, record, rowIdx, colIdx, store) {
metaData.tdAttr = 'data-qtip="' + value + '"';
return value;
};
var dateRender = Ext.util.Format.dateRenderer('m/d/Y');
this.columns=[
//code for all my columns
]
];
this.callParent(arguments);
}
});
Try putting a listener on the store then listen for the onload event get the count and update the field that way. Though there are many ways to do this that is just one.
But in the example above you never load the store you just create it, which is why you see zero.
figured it out, needed to add a listener for the "load" event, not "onLoad". Code below...
Ext.define('APP.store.Store', {
extend: 'Ext.data.Store',
model: 'APP.model.Model',
autoLoad: true,
autoSync: true,
purgePageCount: 0,
proxy: {
type: 'rest',
url: 'json.php',
reader: {
type: 'json',
root: 'users',
successProperty: 'success'
}
},
sortOnLoad:true,
sorters: [{
property: 'last',
direction: 'ASC'
}],
listeners: {
load:{
fn:function(){
var label = Ext.ComponentQuery.query('#countlabel')[0];
label.setText(this.count()+ ' Total Participants);
}
}
}
});

EXTJS 4 Json nested data in grid panel

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.

How to read nested JSON structure with a Sencha Touch Data Model?

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.

Get the clicked JSON element's value with ExtJS

I have a JSON store:
var jsonstore = new Ext.data.ArrayStore({
fields: ['bla', 'blubb'],
data: [ ['bla', 'blubb'],
['blabla', 'blublu'],
['blass', 'hallo'],
['bam', 'guckt'] ]
});
and an extjs listview:
....
,{
xtype: 'listview',
name: 'abrufliste',
store: jsonstore,
id:"ladebereich",
multiSelect: false,
emptyText: 'nix da',
reserveScrollOffset: true,
columns: [ { header: 'Name',
width: .5,
dataIndex: 'NAME' }
....
and a click event:
Ext.ComponentMgr.get('ladebereich').on("click",function (sthis,index,node,e ){
alert("node: "+node.childNodes[0].childNodes[0].innerHTML);});
I want to get the clicked node's value.
I do get the value with
node.childNodes[0].childNodes[0].innerHTML
, however thats a crappy solution.
I want to get the clicked Element from my jsonstore,
any suggestions?
Another way is to add a listener to your listview to respond to any click events on the listview:
,{
xtype: 'listview',
name: 'abrufliste',
store: jsonstore,
id:"ladebereich",
multiSelect: false,
emptyText: 'nix da',
reserveScrollOffset: true,
listeners:
{
click: function(object, selectedIndex, node, event) {
// Get the name corresponding to the selected row.
var rowName = object.store.getAt(selectedIndex).get("Name");
}
},
columns: [ { header: 'Name',
width: .5,
dataIndex: 'NAME' }
it works with
Ext.ComponentMgr.get('ladebereich').on("click",function (sthis,index,node,e ){
var rec = jsonstore.getAt(index);
alert(rec.get("NAME"));
});