Further progress. Please see at http://www.sencha.com/forum/showthread.php?153986-Empty-column-something-I-can-t-get-with-Ext.data.TreeStore-and-or-Ext.tree.Panel
I always appreciate any further advise.
I am trying to develop a simple extJS Ext 4.0.2a script to display some nested data as a Drag&Drop tree.
To try, I use a simple example from http://docs.sencha.com/ext-js/4-0/#!/api/Ext.data.reader.Reader
Data are given as a users.json file:
{
"users": [
{
"id": 123,
"name": "Ed",
"orders": [
{
"id": 50,
"total": 100,
"order_items": [
{
"id" : 20,
"price" : 40,
"quantity": 2,
"product" : {
"id": 1000,
"name": "MacBook Pro"
}
},
{
"id" : 21,
"price" : 20,
"quantity": 3,
"product" : {
"id": 1001,
"name": "iPhone"
}
}
]
}
]
}
]
}
I wish to display data as a tree, whose first level nodes are users, second level nodes are orders, and so on.
From the same doc, I learn how to define my models (I believe):
Ext.define("User", {
extend: 'Ext.data.Model',
fields: [
'id', 'name'
],
hasMany: {model: 'Order', name: 'orders'},
proxy: {
type: 'ajax', // rest
url : 'users.json',
reader: {
type: 'json',
root: 'users'
}
}
})
;
Ext.define("Order", {
extend: 'Ext.data.Model',
fields: [
'id', 'total'
],
hasMany : {model: 'OrderItem', name: 'orderItems', associationKey: 'order_items'},
belongsTo: 'User'
});
Ext.define("OrderItem", {
extend: 'Ext.data.Model',
fields: [
'id', 'price', 'quantity', 'order_id', 'product_id'
],
belongsTo: ['Order', {model: 'Product', associationKey: 'product'}]
});
Ext.define("Product", {
extend: 'Ext.data.Model',
fields: [
'id', 'name'
],
hasMany: 'OrderItem'
});
next, I define a tree store and a tree panel (for some selected fields):
var store = Ext.create('Ext.data.TreeStore', {
model: 'User',
autoLoad: true,
autoSync: true,
root: {
name: "Root node",
id: '0',
expanded: true
},
sorters: [{
property: 'id',
direction: 'ASC' // DESC
}]
});
var tree = Ext.create('Ext.tree.Panel', {
store: store,
displayField: 'name', // what nodes display (default->text)
columns: [{
xtype: 'treecolumn',
text: 'name',
dataIndex: 'name',
width: 150,
sortable: true
}, {
text: 'total',
dataIndex: 'total',
width: 150,
flex: 1,
sortable: true
}, {
text: 'price',
dataIndex: 'price',
width: 50,
flex: 1,
sortable: true
},{
text: 'quantity',
dataIndex: 'quantity',
width: 150,
flex: 1
}, {
text: 'id',
dataIndex: 'id',
flex: 1,
width: 15,
sortable: true
}],
collapsible: true,
viewConfig: {
plugins: {
ptype: 'treeviewdragdrop', // see Ext.tree.plugin.TreeViewDragDrop
nodeHighlightColor : '7B68EE',
nodeHighlightOnDrop : true,
nodeHighlightOnRepair: true,
enableDrag: true,
enableDrop: true
}
},
renderTo: 'tree-div',
height: 300,
width: 900,
title: 'Items',
useArrows: true,
dockedItems: [{
xtype: 'toolbar',
items: [{
text: 'Expand All',
handler: function(){
tree.expandAll();
}
}, {
text: 'Collapse All',
handler: function(){
tree.collapseAll();
}
}]
}]
});
});
I see the panel, the root and the first level users (as subnodes of the root). I do not see any subnodes (orders, order_items and so on).
I looked carefully at a number of posts, improved things quite a lot, but still miss to get a working solution.
I am facing the same task, and first was glad to run into your post!
After 5 hours of exploring the official docs regarding to it:
http://docs.sencha.com/ext-js/4-0/#!/guide/data
http://docs.sencha.com/ext-js/4-0/#!/api/Ext.data.reader.Reader
I was able to populate my nested treestore with nothing better than this:
(in my case the main model is Camgroup which hasMany Camera as 'cams': which allows to use .cams() for every group)
Ext.define('AV.store.sCamgroups', {
extend: 'Ext.data.TreeStore',
model: 'AV.model.Camgroup',
autoLoad: true,
root: {
expanded: true,
text: "Grouped Cameras"
},
proxy: {
type: 'ajax',
url: 'data/camgroups.json',
reader: {
type: 'json',
root: 'camgroups',
successProperty: 'success'
}
},
listeners: {
load: function(thisStore, rootnode, records, successful, eOpts){
records.forEach(function(group){
group.cams().each(function(cam) {
group.appendChild({
text: cam.get('name'),
leaf: true
});
});
});
}
}
});
camgroups.json returns smth like this:
{
success: true,
camgroups: [{
"id" : "group1",
"name" : "Exterior cams",
"cams" : [{
"id" : "cam3",
"name" : "Camera three",
"url" : "...",
"img" : "images/cams/3.png",
"ratio" : 1.33
},{
"id" : "cam4",
"name" : "Camera four",
"url" : "...",
"img" : "images/cams/4.png",
"ratio" : 1.33
}]
}]
}
Hope this will help you though keep looking for a better solution (prob defining a proper reader).
Again, in "Ext.data.reader.Reader" I can see that Reader has config property 'implicitIncludes' which is supposed 'to automatically parse models nested within other models in a response object', but I cannot make it working =(
Cheers,
Ilya
Further progress.
Please see at
http://www.sencha.com/forum/showthread.php?153986-Empty-column-something-I-can-t-get-with-Ext.data.TreeStore-and-or-Ext.tree.Panel
I appreciate any further advise.
I made some progress. It seems I need to modify my json:
{
"children": [ <<<<---- use the same string to insert nested data, see below too
{
"id": 12,
"name": "Ed2",
"children": [] <<<<---- need this line, otherwise, JS tries to load subnodes for ever
},
{
"id": 123,
"name": "Ed",
"children": [ <<<<---- as above
{
"id": 50,
"total": 100,
"info" : "hello",
"name" : "ciao",
"children": [ <<<<---- as above
{
"id" : 20,
"price" : 40,
"quantity": 2,
"children" : { <<<<---- as above
"id": 1000,
"name": "MacBook Pro",
"children": [] <<<<---- as above bis
}
},
{
"id" : 21,
"price" : 20,
"quantity": 3,
"children" : { <<<<---- as above
"id": 1001,
"name": "iPhone",
"children": [] <<<<---- as above bis
}
}
]
}
]
}
]
}
Then the following definition of a model works:
Ext.define("User", {
extend: 'Ext.data.Model',
fields: [
'id', 'name', 'info', 'price', 'quantity', 'order_id', 'product_id'
],
proxy: {
type: 'ajax', //rest
url : 'ex1.json',
reader: {
type: 'json',
root: 'children'
}
}
});
So, it seems that associations among models for the different levels of my nested data are not needed at all.
It works, although I am not sure whether there are drawbacks or not.
I am still looking for your advise, I go by try&mistake, I do not see the underlying logic yet.
Thks.
I have second thoughts. The trick to use a unique string 'children' does not seem so good.
Let me consider a very simple json:
{
"users": [
{
"id": 12,
"name": "Ed2",
"orders": []
},
{
"id": 123,
"name": "Ed",
"orders": [
{
"id": 50,
"info" : "hello",
"name" : "MM",
"leaf" : 'true',
"some_else": []
}]
}
]
}
The extJS tree I wish to get is:
Root
|--ED
|--ED2
|--MM
The model is just
Ext.define("User", {
extend: 'Ext.data.Model',
fields: [
'id', 'name'
],
hasMany: {model: 'Order', name: 'orders'},
proxy: {
type: 'ajax', //rest
url : 'my_file.json',
reader: {
type: 'json',
root: 'users'
}
}
});
Ext.define("Order", {
extend: 'Ext.data.Model',
fields: [
'id', 'name', 'info'
],
belongsTo: 'User'
});
The final output I get is just:
Root
|--ED
|--ED2
is it a mistake of mine, or a missing feature? is there a way out without to change my json?
Thanks a lot
Related
I wish to GET JSON from Django API to model for my ext js Grid.
There is JSON pseudo code :
"type": "FeatureCollection",
"features": [
{
"id": 31,
"type": "Feature",
"geometry": {
"coordinates": [
[
[
[],
[],
[],
[],
[]
]
]
],
"type": "MultiPolygon"
},
"properties": {
"subject": null,
"num_of_agree": 16,
"uroch": "",
"num_allot": null,
"num_fca": "prob-01",
"ar_fca": "34.80",
"expl_ar": 32.2,
"cel_nazn": 3,
"cat_zas": 3,
"video_cat": "D:/work/"
}
},
You can see that there is nested JSON. I need to GET fields from "properties".
So after some google searching, I tried 2 ways.
First it is using of mapping congig.
model:
extend:'Ext.data.Model',
config:'features' ,
fields: [{
name: 'subject',
mapping:features.properties.subject
},{
name:'num_of_agree',
mapping:properties.num_of_agree
},{
name:'uroch',
mapping: properties.uroch
},{...}```
there is grid code:
Ext.define('Foresto.view.cutworkpanel.CutareaGrid', {
extend:'Ext.grid.Grid',
xtype: 'cut-area-grid',
id: 'cut-area-grid',
requires: [
'Ext.grid.plugin.Editable',
on',
'Ext.grid.plugin.RowExpander',
'Foresto.view.cutworkpanel.CutareaModel',
],
title: 'List',
width: '100%',
height: '90%',
hideHeaders: false,
autoScroll: true,
tools: [{
type:'help'
}],
store: {
model:'Foresto.view.cutworkpanel.CutareaModel',
autoLoad: true,
pageSize:0,
proxy: {
type:'ajax',
url:'/api/cutarea-fca/',
reader:{
type:'json',
rootProperty: 'results'
var requestURL = '/api/cutarea-fca/'
}
}
},
plugins: [{
type: 'grideditable',
triggerEvent: 'doubletap',
enableDeleteButton: true,
formConfig: null, // See more below
renderTo: 'map-panel',
defaultFormConfig: {
xtype: 'formpanel',
title:'EDIT',
scrollable: true,
items: {
xtype: 'fieldset'
}
},
columns: [{
text: 'subject',
flex: 1,
minWidth: 200,
dataIndex: 'subject',
editable:true
},{
text:'agreement',
dataIndex:'num_of_agree',
minWidth: 200,
editable:true
},{
text:'сфоткай',
dataIndex:'num_fca',
minWidth: 220,
editable:true
}
and another variant of mod:
``` Ext.define('Foresto.view.cutworkpanel.CutareaModel',{
extend:'Ext.data.Model',
config:'features' ,
fields: [{
name: 'subject',
mapping:function(properties){
return properties.subject;
}
},{
name:'num_of_agree',
mapping:function(properties){
return properties.num_of_agree;
}
},{
name:'uroch',
mapping:function(properties){
return properties.uroch;
}
Both approaches aren't working for me. Please tell me how to fix and what to use.
UPD I use an answer information. I used this method (define record config in store) like that: rootProperty: 'results', record: 'features' //in Store. And config: 'propetries' //in the CutareaModel.js
And it give me only 1 row in grid with: [object Object] [object Object] [object Object] etc. for all of my nubers of fields
You can use the proper rootProperty and record config in the store reader as below
store: {
model:'Foresto.view.cutworkpanel.CutareaModel',
autoLoad: true,
pageSize:0,
proxy: {
type:'ajax',
url:'/api/cutarea-fca/',
reader:{
type:'json',
rootProperty: 'features',
record: 'properties'
}
}
}
rootProperty:'results.features[0].properties', cause features in my JSON is arrive.
so:
store: {
model:'Foresto.view.cutworkpanel.CutareaModel',
proxy: {
type:'ajax',
url:'/api/',
reader:{
type:'json',
rootProperty:'results.features[0].properties',
}
}
}
As you will notice JSON returns different values within same field name and thusly I've binded to required value with dot notation. But I'm using same panel on different classes, so I need to figure out a better way to bind specified value. I've tried to use mapping on BookStatModel but couldn't be success.
How can I achieve for a shorten/roboust usage of data binding to JSON which have different values on same field name.
I can't alter server response;
{
"success": true,
"msg": "OK",
"count": 5,
"data": [
{
"bid": 1000655,
"code": "TOTALPENDING",
"totalcount": 1
},
{
"bid": 1000655,
"code": "TOTALLEFT",
"totalcount": 2
},
I'm getting JSON through VM stores;
// VM
stores: {
bookStore: {
model: 'MyApp.model.base.BookStatModel',
autoLoad: true,
session: true,
proxy: {
url: MyApp.Globals.getUrl() + '/bonustrans/stat/book',
type: 'ajax',
reader: {
type: 'json',
rootProperty: 'data'
}
}
},
// Model itself
Ext.define('MyApp.model.base.BookStatModel', {
extend: 'MyApp.model.base.StatResultModel',
requires: [
'MyApp.Globals',
'MyApp.FldNames'
],
fields: [
{name: 'bid', type: MyApp.FldTypes.INT},
{name: 'code'}
//{name: 'currentBonus', mapping: 'bookStore.data.items.1.totalcount', type: 'integer'},
//{name: 'pendingBonus', mapping: 'bookStore.data.items.0.totalcount', type: 'integer'},
//{name: 'totalBonus', mapping: 'bookStore.data.items.2.totalcount', type: 'integer'}
]
});
and finally bind those data to panel with bind config;
{
xtype: 'infocard',
flex: 1,
margin: '0 5 0 0',
bodyStyle: {
"background-color": "#DFE684"
},
items: [{
xtype: 'container',
layout: {
type: 'hbox'
},
items: [{
xtype: 'container',
layout: {
type: 'vbox',
align: 'middle',
pack: 'end'
},
flex: 2,
items: [{
xtype: 'container',
userCls: 'infocardCount',
bind: {
//In another 'infocard' binds to 'items.0.totalcount'
html: '{bookStore.data.items.1.totalcount}'
//html: '{currentBonus}' //Couldn't render value
},
flex: 1
}, {
xtype: 'component',
height: 10
}, {
xtype: 'container',
userCls: 'infocardCode',
padding: '10',
bind: {
//In another 'infocard' binds to 'items.0.code'
html: '{bookStore.data.items.1.code}'
},
flex: 1
}]
},
Formulas is the answer For your design this should work :
https://fiddle.sencha.com/#view/editor&fiddle/2edq
But my suggestion is to use a bonuses grid where bonustype is a column (currentBonus,pendingBonus,totalBonus)
I'm getting this JSON below and need to format code field' string value to some other text. For example 'TOTALPENDING' will render as "Pending Bonus" and 'TOTALLEFT' to "Current Bonus". How can i achieve to this?
{
"success": true,
"msg": "OK",
"count": 5,
"data": [
{
"bookerid": 103083420,
"code": "TOTALPENDING",
"totalcount": 1
},
{
"bookerid": 103083420,
"code": "TOTALLEFT",
"totalcount": 2
},
Data fetchs through ViewModel stores;
stores: {
bookStore: {
model: 'MyApp.model.base.BookStatModel',
autoLoad: true,
session: true,
proxy: {
url: MyApp.Globals.getUrl() + '/bonustrans/stat/book',
type: 'ajax',
reader: {
type: 'json',
rootProperty: 'data'
}
}
},
For this you need to use convert config inside of model.
In this FIDDLE, I have created a demo using grid, store and model. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('Book', {
extend: 'Ext.data.Model',
fields: ['bookerid', {
name: 'code',
convert: function (v, rec) {
switch (v) {
case 'TOTALPENDING':
v = 'Pending Bonus';
break;
case 'TOTALLEFT':
v = 'Current Bonus';
break;
default:
v = '';
break;
}
return v;
}
}, 'totalcount'],
});
Ext.define('TestViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.test',
stores: {
books: {
model: 'Book',
proxy: {
type: 'ajax',
url: 'book.json',
reader: {
type: 'json',
rootProperty: 'data',
keepRawData: true
}
},
autoLoad: true
}
}
});
Ext.create({
xtype: 'container',
layout: 'vbox',
fullscreen: true,
renderTo: Ext.getBody(),
viewModel: {
type: 'test'
},
items: [{
xtype: 'container',
userCls: 'infocardCount',
margin: 10,
bind: {
html: '<small>If value is 0 then we can use pipes and in that case you need to pass 0 inside of string like this <b> books.data.items.0.totalcount || "0"</b> </small><br><br> <b style="color: #3c3c3c;background: #ccc;padding: 10px;margin: 10px;">{books.data.items.0.totalcount || "0"}</b>'
}
}, {
xtype: 'grid',
flex: 1,
width: '100%',
title: 'Book Data',
bind: {
store: '{books}'
},
columns: [{
text: 'BOOK ID',
flex: 1,
dataIndex: 'bookerid'
}, {
text: 'CODE',
dataIndex: 'code',
flex: 1
}, {
text: 'TOTAL',
flex: 1,
dataIndex: 'totalcount'
}]
}]
});
}
});
JSON FILE
{
"success": true,
"msg": "OK",
"count": 5,
"data": [{
"bookerid": 103083420,
"code": "TOTALPENDING",
"totalcount": 0
}, {
"bookerid": 103083421,
"code": "TOTALLEFT",
"totalcount": 15
}, {
"bookerid": 103083422,
"code": "TOTALPENDING",
"totalcount": 12
}, {
"bookerid": 103083423,
"code": "TOTALLEFT",
"totalcount": 10
}, {
"bookerid": 103083424,
"code": "TOTALLEFT",
"totalcount": 16
}]
}
I have managed to implement a treepanel and everything seems to be working. I have data like so ( see below). My fields I "name" which holds below things like "ItemA", "ProductA" which are nodes and the "Iron" which is a leaf and a property called "Available" which is true / false (boolean but represented as a string).
When clicking the sort column for the boolean, it sorts them but sorts then as whole. i.e. I would only want to sort the booleans in each group. Currently it sorts them as group of items it seems. So the nodes under ItemB change order, not just the order of the boolean column. I hope this makes sense.
I have the column model set to this
sortType: Ext.data.SortTypes.asUCString
I have also tried changing the property of "folderSort" between true and false in the treepanel but it makes no difference.
Any ideas?
Here's an example of my data to try and visualize it better.
ItemA
ProductA
Iron true
ItemB
Product123
House true
Garage false
Misc false
Product1443
HouseF true
NewItem false
As I understand from your question, you can't only sort the leafs instead of nodes. So, you can specify your leaf and node models and then set the "available" property to leafs. Please check this fiddle: https://fiddle.sencha.com/#fiddle/upv
If that's not what you are looking for or it's not possible to change your treepanel model, please change the fiddle and add your treepanel with its model. Hope it helps.
Ext.define('model.ItemsRoot', {
extend: 'Ext.data.TreeModel',
childType: 'model.Items',
fields: [{
name: 'text',
mapping: 'name'
},{
name: 'Available',
type: 'boolean'
}]
});
Ext.define('model.Items', {
extend: 'Ext.data.TreeModel',
childType: 'model.Products',
fields: [{
name: 'text',
mapping: 'name'
}]
});
Ext.define('model.Products', {
extend: 'Ext.data.TreeModel',
childType: 'model.ItemNames',
fields: [{
name: 'text',
mapping: 'name'
}]
});
Ext.define('model.ItemNames', {
extend: 'Ext.data.TreeModel',
fields: [{
name: 'text',
mapping: 'name'
}]
});
var treeStore = Ext.create('Ext.data.TreeStore', {
model: 'model.ItemsRoot',
root: {
text: '',
expanded: true,
children: [{
name: "Item A",
expanded: true,
children: [{
name: "Product A",
expanded: true,
children: [{
name: "Iron",
leaf: true,
Available: true
}]
}]
}, {
name: "Item B",
expanded: true,
children: [{
name: "Product B",
expanded: true,
children: [{
name: "House",
Available: false,
leaf: true
}, {
name: "Garage",
leaf: true,
Available: true
}, {
name: "Misc",
leaf: true,
Available: false
}]
}, {
name: "Product C",
expanded: true,
children: [{
name: "House F",
leaf: true,
Available: true
}, {
name: "New Item",
leaf: true,
Available: false
}]
}]
}]
}
});
var treePanel = Ext.create('Ext.tree.Panel', {
store: treeStore,
rootVisible: false,
columns: [{
xtype: 'treecolumn', //this is so we know which column will show the tree
text: 'Items',
flex: 2,
sortable: true,
dataIndex: 'name'
}, {
//xtype: 'checkcolumn',
header: 'Available',
dataIndex: 'Available',
//stopSelection: false,
//menuDisabled: true,
editor: {
xtype: 'checkbox',
}
}],
renderTo: Ext.getBody()
});
I'm very new to Sencha touch. I have to Load JSON data in a list.
My Panel.js
Ext.define('MyApp.view.MyPanel', {
extend: 'Ext.Panel',
requires: [
'Ext.Toolbar',
'Ext.dataview.List',
'Ext.XTemplate'],
config: {
items: [{
xtype: 'toolbar',
docked: 'top',
title: 'Test'
}, {
xtype: 'list',
itemTpl: [
'\'<tpl for="polls">\',',
' \'<div> {title}</div>\',',
' \'<div> {uri}</div>\',',
'\'</tpl>\','],
store: 'MyStore'
}]
}
});
MyModel.js
Ext.define('MyApp.model.MyModel', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.Field',
'Ext.data.proxy.JsonP'],
config: {
fields: [{
name: 'title'
}, {
name: 'uri'
}]
}
});
MyStore.js
Ext.define('MyApp.store.MyStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.MyModel',
'Ext.data.proxy.JsonP',
'Ext.data.reader.Json'],
config: {
autoLoad: true,
model: 'MyApp.model.MyModel',
storeId: 'MyStore',
proxy: {
type: 'jsonp',
url: 'my_web_site_url/polls',
reader: {
type: 'json',
rootProperty: 'polls'
}
}
}
});
The JSON FILE has the following format..
{
"polls": [
{
"title": "how r u?",
"uri": "/polls/answer1"
}
]
}
and my_web_site_url/polls/uri will give u the
{
"choices": [
{
"choice": "fine",
"votes": 0
},
{
"choice": "good",
"votes": 0
},
{
"choice": "sad",
"votes": 0
}
],
"title": "how r u?",
"uri": "/polls/answers1"
}
When I try 'Load Data' in the Sencha Architect it shows:
Unable to load the data Using the supplied Configuration open in Browser my_website_url/polls