Extracting Nested JSON from Store Record? - sencha-touch-2

I'm working from an example based on the comments in the Sencha documentation. I am able to extract the top-level information (id,name,last) but I can't figure out how to extract the products from each record. I was hoping that it would be as simple as requesting that part of the record but aProduct is always null:
var name = aRecord.get('name'); // Good
var lastName = aRecord.get('last'); // Good
var aProduct = aRecord.get('products'); // Null
I'm including all the code.
JSON:
[
{
"id": 1,
"name": "Ed",
"last": "Bar",
"products": [
{
"short_name": "Product1",
"name": "Another Product"
},
{
"short_name": "Product2",
"name": "Second Product"
}
]
},
{
"id": 2,
"name": "Foo",
"last": "Bar",
"products": [
{
"short_name": "Product1",
"name": "Another Product"
},
{
"short_name": "Product2",
"name": "Second Product"
}
]
}
]
app.js:
Ext.application({
name: 'SenchaFiddle',
models: ['Product', 'User'],
stores: ['UserStore'],
views: [],
controllers: [],
launch: function () {
Ext.create('Ext.Panel', {
fullscreen: true,
html: 'Test...'
});
var userStore = Ext.getStore('UserStore');
console.log(userStore);
console.log('--- Data ---');
userStore.each(function (val) {
console.log(val.get('name'));
});
console.log('--- Done ---');
userStore.load({
params: {},
scope: this,
callback: function (records, operation, success) {
console.log("status=" + success);
console.log("Number Records=" + records.length);
for (var i = 0; i < records.length; i++) {
var aRecord = records[i];
console.log(aRecord);
var name = aRecord.get('name');
var lastName = aRecord.get('last');
var productList = aRecord.get('products');
console.log('(Short, First, Last)=(' + productList + ',' + name + ',' + lastName + ')');
for (var j=0; j<productList.length; j++) {
console.log(productList[j].name + " / " + productList[j].short_name);
}
}
}
});
}
});
User Model:
Ext.define('SenchaFiddle.model.User', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'id', type: 'int'},
{name: 'name', type: 'string'},
{name: 'last', type: 'string'}
],
// we can use the hasMany shortcut on the model to create a hasMany association
hasMany: {model: 'Product', name: 'products', "associationKey": 'products'}
}
});
Product Model:
Ext.define('SenchaFiddle.model.Product', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'id', type: 'int'},
{name: 'user_id', type: 'int'},
{name: 'short_name', type: 'string'},
{name: 'name', type: 'string'}
]
}
});
User Store:
Ext.define('SenchaFiddle.store.UserStore', {
extend: 'Ext.data.Store',
config: {
model: 'SenchaFiddle.model.User',
autoLoad: true,
proxy: {
type: 'ajax',
url: 'users.json',
reader: {
type: 'json'
//rootProperty: 'users'
}
}
},
load: function () {
this.callParent(arguments);
console.log("User Store Loaded\n");
}
});

Nice work, you are very close!
Add a products field to your user model:
fields: ['products',
{name: 'id', type: 'int'},
{name: 'name', type: 'string'},
{name: 'last', type: 'string'}
]
Stick w/Sencha, the whole package can be a little overwhelming and admittedly confusing (even after a couple years of use) but it definitely get better.
Brad

Related

Insert data into a store immediately after the store is loaded?

I've create a simple app that loads data from a json store and draws it on the screen. What I need to be able to do is add to the store on the client side (I don't control the source data). So, in either the store load:funciton() or in the MainController, if it's not too late, I want to insert a few rows at the beginning so these records appear before John, Paul, George, and Ringo. I've included all of my Javascript so the code is complete.
EmployeeModel:
Ext.define('Sencha.model.Employee', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'firstName', type: 'string'},
{name: 'lastName', type: 'string'},
{
name: 'fullName',
type: 'string',
convert: function (value, record) {
firstName = record.data.firstName;
lastName = record.data.lastName;
fullName = firstName + " " + lastName;
return fullName;
}
}
]
},
load: function () {
console.log("Employee model");
this.callParent(arguments);
}
});
EmployeeStore:
Ext.define('Sencha.store.EmployeeStore', {
extend: 'Ext.data.Store',
requires: [],
config: {
model: 'Sencha.model.Employee',
autoLoad: true,
defaultRootProperty: 'items',
proxy: {
type: 'ajax',
url: 'employees.json',
reader: {
type: 'json',
rootProperty: 'items'
}
}
},
load: function () {
console.log("EmployeeStore");
this.callParent(arguments);
}
});
Controller: (Trying to get the store and print the values)
Ext.define('Sencha.controller.MainController', {
extend: 'Ext.app.Controller',
requires: [],
config: {
},
launch: function () {
console.log("Main Controller...");
var empStore = Ext.getStore('EmployeeStore');
console.log(empStore.length);
empStore.each(function (val) { // Not working
var firstName = val.get('firstName');
console.log(firstName);
});
}
});
app.js:
Ext.Loader.setConfig({enabled: true});
Ext.application({
name: "Sencha",
models: ['Employee'],
stores: ['EmployeeStore'],
views: [],
controllers: ['MainController'],
launch: function () {
console.log("Launching");
var aList = Ext.create("Ext.List", {
fullscreen: true,
store: 'EmployeeStore',
itemTpl: "{lastName}, {firstName} - {fullName}"
});
Ext.Viewport.add(aList);
}
});
employees.json:
{"items": [
{ "firstName": "John", "lastName": "Lennon" },
{ "firstName": "Paul", "lastName": "McCartney" },
{ "firstName": "George", "lastName": "Harrison" },
{ "firstName": "Ringo", "lastName": "Starr" }
]}
Take autoload off of your store, load the store in your launch function, and use a callback to add your records:
launch: function () {
var empStore = Ext.getStore('EmployeeStore');
empStore.load(function() {
empStore.insert(0, [ /*records to insert*/ ]);
});
}

TreePanel with an specific TreeStore

I've got the flollowing issue:
I'm building a TreePanel with data of people but I don't know how to define the model of it without defineing : leaf, cls and text attributes. I wan't that "Name" would be the node text of each node .
My model is defined as following:
Ext.define('People', {
extend: 'Ext.data.Model',
fields: [
{name: 'Name', type: 'string'},
{name: 'Surname', type: 'string'},
{name: 'Email', type: 'string'}
{name: 'BirthDate', type: 'string'}
]
});
My TreeStore (for the moment with static data, but it will be load from an ajax call to the server that will return a list of server person model). Obviously I don't want to define leaf, text and cls attributes in my server model:
Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [
{
"Name":"Juan",
"Surname":"Hoz",
"Email": "user#domain.com",
"BirthDate":"19801205"
},
{
"Name":"Marta",
"Surname":"Hoz",
"Email": "user2#domain.com",
"BirthDate":"19831210"
}
}
});
My TreePanel is defined as following:
Ext.create('Ext.tree.Panel', {
id: 'treePersonId',
store: mystore,
hideHeaders: true,
rootVisible: false,
title: 'Persons',
collapsible: true,
resizable:true
});
Can anyone helps me to find the correct way to do this?
Thank you very much,
Juan
Ext.define('Person', {
extend: 'Ext.data.Model',
fields: [{
name: 'Name',
type: 'string'
}, {
name: 'Surname',
type: 'string'
}, {
name: 'Email',
type: 'string'
}, {
name: 'BirthDate',
type: 'string'
}]
});
Ext.require('*');
Ext.onReady(function() {
var store = Ext.create('Ext.data.TreeStore', {
model: 'Person',
root: {
expanded: true,
children: [{
"Name": "Juan",
"Surname": "Hoz",
"Email": "user#domain.com",
"BirthDate": "19801205"
}, {
"Name": "Marta",
"Surname": "Hoz",
"Email": "user2#domain.com",
"BirthDate": "19831210"
}]
}
});
Ext.create('Ext.tree.Panel', {
renderTo: document.body,
store: store,
hideHeaders: true,
rootVisible: false,
columns: [{
xtype: 'treecolumn',
dataIndex: 'Name',
flex: 1
}]
});
});

Loading associated data in Sencha Touch without nesting

I'm working on a basic Sencha Touch application that displays a list of text messages and the name of an associated user that sent the message. I have followed the tutorials online on how to setup model associations but each tutorial assumes that the server produces data with a nested structure.
The data I am working with has a flat structure with primary/foreign key relationships, and I cannot figure out how to get Sencha to load both stores from a single response.
model/User.js
Ext.define('App.model.User', {
extend: 'Ext.data.Model',
config: {
fields: [
{ name: 'uid', type: 'number' },
{ name: 'name', type: 'string' },
]
}
});
store/Users.js
Ext.define('App.store.Users', {
extend: 'Ext.data.Store',
config: {
model: 'App.model.User',
autoLoad: true,
}
});
model/Message.js
Ext.define('App.model.Message', {
extend: 'Ext.data.Model',
config: {
fields: [
{ name: 'id', type: 'number' },
{ name: 'uid', type: 'number' },
{ name: 'message', type: 'string' }
],
associations: [{
type: 'belongsTo',
model: 'App.model.User',
primaryKey: 'uid',
foreignKey: 'uid'
}],
proxy: {
type: 'jsonp',
url: 'messages.json',
reader: {
type: 'json',
rootProperty: 'req_messages'
}
}
}
});
store/Messages.js
Ext.define('App.store.Messages', {
extend: 'Ext.data.Store',
config: {
model: 'App.model.Message',
autoLoad: true,
}
});
The messages are correctly loaded and displayed by my application (sample JSON response below), but I cannot figure out how to get the associated users to be loaded into the store. Can this be solved with a configuration, or will I need a custom reader? Any help appreciated!
Sample JSON
{
"users": [{
"uid": "1",
"name": "John"
}, {
"uid": "3033",
"name": "Noah"
}],
"req_messages": [{
"id": "539",
"uid": "1",
"message": "my message"
}, {
"id": "538",
"uid": "1",
"message": "whoops"
}, {
"id": "534",
"uid": "3033",
"message": "I love pandas."
}]
}
I've never really worked with associations and I went through the document to try to find something that would load two stores with on request, but I couldn't find anything. So here's how I would do it :
Model
Ext.define('App.model.User', {
extend: 'Ext.data.Model',
config: {
fields: [
'uid',
'name'
]
}
});
Ext.define('App.model.Message', {
extend: 'Ext.data.Model',
config: {
fields: [
'id',
'message',
'uid'
],
associations: { type: 'hasOne', model: 'User', primaryKey: 'uid', foreignKey: 'uid'}
}
});
Stores
Ext.define('App.store.Users', {
extend: 'Ext.data.Store',
config: {
model: 'App.model.User',
autoLoad: true,
proxy: {
type: 'ajax',
url: 'http://www.titouanvanbelle.fr/test.json',
reader: {
type: 'json',
rootProperty: 'users'
}
},
listeners:{
load:function(s,r,success,op){
var msgs = JSON.parse(op.getResponse().responseText).req_messages;
Ext.each(msgs, function(msg) {
Ext.getStore('Messages').add(Ext.create('App.model.Message',msg));
});
}
}
}
});
Ext.define('App.store.Messages', {
extend: 'Ext.data.Store',
config: {
model: 'App.model.Message'
}
});
List
Ext.define("App.view.Main", {
extend: 'Ext.Panel',
config: {
fullscreen: true,
layout:'fit',
items: [{
xtype:'list',
store:'Messages',
itemTpl: new Ext.XTemplate(
'<tpl for=".">',
'{[this.getUserName(values)]} : {message}',
'</tpl>',
{
getUserName(v){
var s = Ext.getStore('Users'),
u = s.getAt(s.find('uid',v.uid));
return u.get('name');
}
}
)
}]
}
});
And you'd get something like this :
Hope this helps. If you need explanation, let me know.

How to filter the Store?

Who knows how to filter the Store right?
I tried to do it in listener of leafItemTap of Nested List, but my leaf items not tapping now. Massage in console: "Uncaught TypeError: Cannot call method 'filter' of undefined "
Here is Nested list, where Store must be filtered:
Ext.define('Application.view.SplitView', {
extend: 'Ext.Container',
xtype: 'splitview',
config: {
layout: 'card',
store: null
},
initialize: function() {
this.nestedList = Ext.create('Ext.NestedList', {
title : 'Рецепты',
detailCard: Ext.create('Application.view.MainDetail'),
store: this.getStore(),
listeners: {
scope: this,
leafitemtap: this.onLeafItemTap
}
});
this.setItems([this.nestedList]);
},
updateStore: function(newStore) {
if (this.nestedList) {
this.nestedList.setStore(newStore);
}
},
onLeafItemTap: function(nestedList, list, index, node, record, e) {
var psn = record.get('text');
console.log(psn);
var detailCard = nestedList.getDetailCard();
var store = Ext.getStore('Application.store.DetailStore');
store.filter('title', 'Brownies');
console.log(store);
}
});
This is my Store, which I want to filter:
Ext.define('Application.store.DetailStore', {
extend: 'Ext.data.Store',
config: {
model: 'Application.model.DetailModel',
autoLoad :true,
sorters: 'title',
grouper : function(record) {
return record.get('title')[0];
},
proxy: {
type: 'ajax',
url : '/data/data1.php',
reader: {
type: 'json',
rootProperty:'recipes'}
}
}
});
And Store's model:
Ext.define('Application.model.DetailModel', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'title', type: 'string'},
{name: 'serves', type: 'string'},
{name: 'cooktime', type: 'string'},
{name: 'ingridients', type: 'string'},
{name: 'picture', type: 'string'},
{name: 'kitchen', type: 'string'},
{name: 'category', type: 'string'},
{name: 'instructions', type: 'string'}
]
},
fullName: function() {
var d = this.data,
names = [
d.title
];
return names.join(" ");
}
});
I'm new in Sencha and every advice will be useful
The following error means the object which you're calling the filter function on is undefined
"Uncaught TypeError: Cannot call method 'filter' of undefined "
In your case, the store is undefined.
Try to get it by doing :
var store = Ext.getStore('DetailStore');
Also, you could check what stores are in the StoreManager by doing :
console.log(Ext.data.StoreManager.all);
Hope this helps

upgrading array store on combo box from 4.07 to 4.1

The below configuration works on 4.07 but not 4.1.
On 4.1 i can see that my combo has 3 items. It just doesn't reader the displayField and valueField.
i'm using the mvc architecture.
In my view
{
xtype: 'combobox',
id: 'ProofRequired',
name: 'ProofRequired',
fieldLabel: 'Proof Required',
displayField: 'Name',
store: 'ProofRequired',
triggerAction: 'all',
queryMode: 'local',
valueField: 'Id'
},
in my app.js
stores: [ 'VarnishType'],
and my store
Ext.define('Mis.store.ProofRequired', { extend: 'Ext.data.Store',
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: true,
storeId: 'ProofRequired',
clearOnPageLoad: false,
data: [
{
Id: '1',
Name: 'Digital'
},
{
Id : '2',
Name : 'PDF'
},
{
Id : '3',
Name : 'Other'
}
],
proxy: {
type: 'ajax',
reader: {
type: 'array'
}
},
fields: [
{
Id: 'Id',
Name: 'Name'
}
]
}, cfg)]);
}
});
The below worked for me. I'm 100% sure why. I believe i need to put quotes around the field names.
Ext.define('Mis.store.ProofRequired', {
extend: 'Ext.data.Store',
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: true,
storeId: 'ProofRequired',
clearOnPageLoad: false,
fields: ['Id', 'Name'],
data : [
{"Id":"1", "Name":"Digital"},
{"Id":"2", "Name":"PDF"},
{"Id":"3", "Name":"Other"}
],
proxy: {
type: 'ajax',
reader: {
type: 'array'
}
}
}, cfg)]);
}
});