Generate items in Ext.dataview.List from hasMany models the MVC way - sencha-touch

I have a Blog model with hasMany Posts (and many other fields). Now I want to list these posts in a List-view like that:
[My post #1]
[My post #2]
[My post #3]
As far as the API described, I'm able to pass either a store or a data attribute to Ext.dataview.List. But I was not able to find out how to pass the hasMany records to the list so it will display an item for each of them.
Do I really have to create another store? Isn't it possible to configure my dataview to something like store: 'Blog.posts' or data: 'Blog.posts' or even records: 'Blog.posts'?

Extend the dataview.List to define the itemtpl to loop through the posts
itemTpl: new Ext.XTemplate(
'<tpl for="**posts**" >',
'<div>{TheBlogPost}</div>',
'</tpl>'
)

As #Adam Marshall said, this doesn't work as easy as I imagined.

Sencha autogenerates stores from associations if you know how to access them.
So you simply can switch out the list's store for the autogenerated "substore" when it has loaded.
This approach probably has some problems, e.g. when listpaging plugin is used, but it is quick.
Example:
MODELS
Ext.define('Conversation', {
extend: 'Ext.data.Model',
config: {
fields: [
],
associations:
[
{
type: 'hasMany',
model: "Message",
name: "messages",
associationKey: 'messages'
}
]
}
});
Ext.define('Message' ,
{
extend: "Ext.data.Model",
config: {
idProperty: 'id_message',
fields: [
{ name: 'text', type: 'string' },
{ name: 'date', type: 'string' },
{ name: 'id_message', type: 'int' },
{ name: 'me', type: 'int'} // actually boolean
]
}
}
);
JSON
[
{
"messages": [
{"id_message": 11761, "date": 1378033041, "me": 1, "text": "iiii"},
{"id_message": 11762, "date": 1378044866, "me": 1, "text": "hallo"}
]}
]
CONTROLLER
this.getList().getStore().load(
{
callback: function(records, operation, success) {
//IMPORTANT LINE HERE:
getList().setStore(Ext.getStore(me.getList().baseStore).getAt(0).messages());
},
scope: this
}
);
LIST-VIEW
{
flex: 1,
xtype: 'list',
itemId: 'ConversationList',
data: [],
store: 'ConversationStore',
baseStore: 'ConversationStore',
itemTpl:
' {[app.util.Helpers.DateFromTimestamp(values.date)]}<br><b>{name}</b>' +
' {[app.util.Helpers.fixResidualHtml(values.text)]} </div>' +
},

Related

Display all associated children with wsapi.Store

I've been searching for a way to display all the defects for a project and it's
children in Rally, however I can't seem to find the right way to go about this.
In the constructor it seems there is no parent property, however I've seen this property used in previous versions using wsapiStore. What is the correct way of doing this now?
Here's a look at my code:
config.json:
{
"name": "BasicRallyGrid",
"className": "CustomApp",
"server": "https://rally1.rallydev.com",
"sdk": "2.1",
"javascript": [
"App.js"
],
"css": [
"app.css"
]
}
Call to Store:
this.myStore= Ext.create('Rally.data.wsapi.Store', {
model: 'Defect',
autoLoad: true,
filters: myFilters,
/*filters: Ext.create('Rally.data.wsapi.Filter', {
property: 'Parent',
operator: '=',
value: "SomeParent"
}),
listeners: {
load: function (myStore) {
if (!this.myStore) {
this._createGrid(myStore);
}
},
scope: this
},
fetch: ['FormattedID', 'Name', 'Severity', 'Iteration', 'Project']
});
}
},
My Grid code:
_createGrid: function (myStore) {
this.myGrid = Ext.create('Rally.ui.grid.Grid', {
store: myStore,
columnCfgs: [
'FormattedID', 'Name', 'Severity', 'Iteration', 'Project'
]
});
this.add(this.myGrid);
Any help would be greatly appreciated. Also, as this is my first question here, if I broke some etiquette please let me know so I can avoid it in future posts.
Thank you!
You just need to use project scoping... Check out this guide: https://help.rallydev.com/apps/2.1/doc/#!/guide/data_stores-section-scoping
By default your store will inherit your global scoping, so I would have expected it to just work, but depending on what you're doing you may have to explicitly specify your project scope + up/down.

How to add custom data in a story board?

Question 1: Is it possible to add custom data (Ex: testcase count : 5) to each card in a story board? If so, how? I couldn't find an example or specific information in documentation.
Question 2: Is it possible to get testcase count (including child story testcases)for a highlevel story in one query?
Please let me know. Here's my code
Ext.define('Rally.Story.View', {
extend: 'Rally.app.App',
launch: function() {
this.add({
xtype: 'rallyfieldvaluecombobox',
fieldLabel: 'Filter by Target Release:',
model: 'UserStory',
field: 'c_TargetRelease',
value: '15.0',
listeners: {
select: this._onSelect,
ready: this._onLoad,
scope: this
}
});
},
_onLoad: function() {
this.add({
xtype: 'rallycardboard',
types: ['User Story'],
attribute: 'ScheduleState',
readOnly: true,
fetch: ['Name', 'TestCases', 'c_StoryType', 'c_TargetRelease', 'PlanEstimate', 'Priority', 'TaskEstimateTotal', 'TaskRemainingTotal'],
context: this.getContext(),
cardConfig: {
editable: false,
showIconsAndHighlightBorder: false,
fields: ['Name', 'c_StoryType', 'c_TargetRelease', 'PlanEstimate', 'c_PriorityBin', 'Parent', 'TestCases', 'TaskEstimateTotal', 'TaskRemainingTotal']
},
storeConfig: {
filters: [
{
property: 'c_StoryType',
value: 'SAGA Feature'
},
{
property: 'c_TargetRelease',
operator: '=',
value: this.down('rallyfieldvaluecombobox').getValue()
}
]
}
});
},
_onSelect: function() {
var board = this.down('rallycardboard');
board.refresh({
storeConfig: {
filters: [
{
property: 'c_StoryType',
value: 'SAGA Feature'
},
{
property: 'c_TargetRelease',
operator: '=',
value: this.down('rallyfieldvaluecombobox').getValue()
}
]
}
});
},
});
Here's a sample card I made that contains the test case count:
You can add a field by simply including an object with some rendering information in it instead of just a simple string in the fields array in the cardConfig:
cardConfig: {
fields: [
'Name', //simple string field to show
{
name: 'TCCount', //field name
hasValue: function() {return true;}, //always show this field
renderTpl: Ext.create('Rally.ui.renderer.template.LabeledFieldTemplate', {
fieldLabel: 'Test Case Count', //the field label
valueTemplate: Ext.create('Ext.XTemplate',
['{[this.getTestCaseCount(values)]}',
{getTestCaseCount: function(data) { return data.Summary.TestCases.Count;}}])
})
},
//additional string fields
'PlanEstimate', 'Parent', 'TestCases', 'TaskEstimateTotal', 'TaskRemainingTotal']
}
This ended up being less straightforward than I thought it might be, but at least it is doable. The key part is using the LabeledFieldTemplate, specifying a field label and a value template to actually render the content.
You'll also notice the little beaker status icon in the footer which is automatically rendered because TestCases was included in the fields list.
As for your second question there is no roll up field on story for the total number of test cases included on child stories.

Model with associations, 1 request fill 2 components best practice

What would be the best practice or design approach for the following scenario:
There is a json been returned from the server that has information about people and their addresses
I need to show a form with the general information of the person plus a list with every address.
In this list it is mandatory that each address is an item of the list because it will be multiselect true in order to do something else.
What I have done is:
a)define a model "Persona" with a hasMany relation to "Direccion"(spanish for address), my proxy is here in the model
b)define a model "Direccion"
c)define a list and try to play with the itemTpl config in order to display 1 address per itemList but so far I can only display all the addresses for a given person in the same itemList.
Is there a way to achieve this ?
Is this approach good given this scenario?
I was trying to do only 1 request and have only 1 store to fill out this 2 components but now I'm having doubts about it.
So what would be the best design/practice given this scenario?
JSON response
{
"personas": [
{
"id": 1,
"nombre": "jon",
"apellido": "caballero",
"direcciones": [
{
"direccionId": 1,
"calle": "fco villa",
"colonia": "barona"
},
{
"direccionId": 2,
"calle": "duraznos",
"colonia": "canutillo"
}
]
}
]
}
Models
Ext.define('Associations.model.Direccion', {
extend: 'Ext.data.Model',
config: {
idProperty: 'direccionId',
fields: [
{ name: 'calle', type: 'auto' },
{ name: 'colonia', type: 'auto' }
]
}
});
Ext.define('Associations.model.Persona', {
extend: 'Ext.data.Model',
requires: ['Associations.model.Direccion'],
config: {
fields: [
{ name: 'nombre', type: 'auto' },
{ name: 'apellido', type: 'auto' },
],
hasMany:[
{
foreignKey: 'direccionId',
associationKey: 'direcciones',
name: 'direcciones',
model: 'Associations.model.Direccion'
}
],
proxy: {
type:'ajax',
url: 'data/respuesta.json',
reader: {
type:'json',
rootProperty:'personas'
}
}
}
});
Store
Ext.define('Associations.store.Persona', {
extend: 'Ext.data.Store',
requires: [
'Associations.model.Persona'
],
config: {
model: 'Associations.model.Persona',
autoLoad: true
}
});
List
Ext.define('Associations.view.PersonaList', {
extend: 'Ext.List',
xtype: 'personalist',
config: {
onItemDisclosure: true,
emptyText: 'No se encontraron personas',
store: 'Persona',
padding: 10,
margin: 10,
itemTpl : [
'<tpl for="direcciones">',
'<li>Colonia {colonia}</li>',
'<li>Calle {calle}</li>',
'</tpl>',
].join('')
}
});
Any ideas?
Thanks in advance.
When you do model.load() and the model has a hasMany relation to another model a store for the child objects is autogenerated therefore the best approach would be to load the model get the store of the child records and set it to the list.

How to set dynamic url in sencha touch using store?

I am new for this platform, Now i am unable to set dyanimic url using category id and token.
What i want:
I have list different items, which have different ids but same token, token(tokent is same one user) getting from login phase. I want to get value accorading to category id from the server.
Here is the my model:
Ext.define('MyApp.model.CategoryDisplayModelMenu', {
extend: 'Ext.data.Model',
config: {
fields: [
/*'cat_id',*/
'category',
'name',
],
belongsTo: "MyApp.model.CategoryDisplayModel"
}
});
and another related model is:
Ext.define('MyApp.model.CategoryDisplayModel', {
extend: 'Ext.data.Model',
requires: ['MyApp.model.CategoryDisplayModelMenu'],
config: {
fields: [
{name:'data', mapping: 'data'},
{name:'name'},
{name: 'category'},
{name: 'author'},
],
}
});
What i am set in store, but could not work:
Ext.define('MyApp.store.CategoryValueStore', {
extend: 'Ext.data.Store',
alias: 'store.CategoryValueStore',
requires: [
'MyApp.model.CategoryDisplayModel'
],
config: {
model: 'MyApp.model.CategoryDisplayModel',
storeId: 'categoriesvaluestore',
proxy: {
type: 'rest',
url: 'http://horror/myapp/api/word/searched_words/catID/'+ 1+'/'+ SDSILLYTOKEN+'/'+650773253e7f157a93c53d47a866204dedc7c363,
noCache: false,
reader: {
type: 'json',
rootProperty: ''
} } }
});
How to set above url, dynamic, cat id and token may be differnt.
But it works when i set these in store
Ext.define('MyApp.store.ArchitectureDisplayStore',{
extend: 'Ext.data.Store',
requires:[
'MyApp.view.Main'
],
config:
{
model: 'MyApp.model.CategoryDisplayModel',
autoLoad:true,
id:'Category',
proxy:
{
type: 'ajax',
url : 'http://horror/myapp/api/word/searched_words/catID/1/SDSILLYTOKEN/650773253e7f157a93c53d47a866204dedc7c363', // file containing json data
reader:
{
rootProperty:''
} } }
});
In View , I set getting value on list like this:
Ext.define("MyApp.view.ArchitectureDisplayMain", {
extend: 'Ext.Container',
alias: "widget.architecturewords",
config: {
{
xtype: 'list',
scrollable: true,
itemId: 'demolist',
itemTpl: [
'<div><tpl for="data"><ul class="catList">{name} -test- {category}</ul> <ul>{author}</ul></tpl></div>'
],
store: 'categoriesvaluestore',
}
}
});
My category display model:
Ext.define('MyApp.model.CategoryModelMenu', {
extend: 'Ext.data.Model',
config: {
fields: [
'cat_id',
'category_name',
],
belongsTo: "MyApp.model.CategoryModel"
}
});
and
Ext.define('MyApp.model.CategoryModel', {
extend: 'Ext.data.Model',
requires: ['MyApp.model.CategoryModelMenu'],
config: {
fields: [
{name:'data', mapping: 'data'},
{name: 'cat_id'},
{name: 'category_name'},
],
}
});
EDIT:
Ext.define('MyApp.view.Category', {
extend: 'Ext.List',
alias: "widget.category",
config: {
title: 'Stores',
cls: 'category-data',
scrollable: false,
store: 'CategoryStore',
itemTpl: [
'<div class="categoryListings">',
'<tpl for="data">',
'<span onClick="catOption({cat_id})">{category_name}</span> ',
'</tpl>',
'</div>',
].join('')
}
//}
});
function catOption(id){
console.log("ID--"+id);
var tokan= '650773253e7f157a93c53d47a866204dedc7c363';
Ext.Viewport.remove(Ext.Viewport.getActiveItem(), true);
Ext.Viewport.add([
{ xtype: 'wordsview' }
]);
} and others
In wordsview, I like to display respective words of clicked category.
It is ok, when click this, first item of id p1, it shows next view.
Please tell me, How to get dynamic data accorading to its category id and token. please give some solution.Thank you advance.
If i understood you correctly
Let's say if you have category id and token in localStorage.
You can do like this
proxy:
{
type: 'ajax',
url : 'http://horror/myapp/api/word/searched_words/catID/'+localStorage.catId+'/SDSILLYTOKEN/'+localStorage.token,
reader:{
rootProperty:''
}
}
OR
Do as #Alex posted. That is better way.. Like
function catOption(id){
console.log("ID--"+id);
var token= '650773253e7f157a93c53d47a866204dedc7c363';
var url = 'http://horror/myapp/api/word/searched_words/catID/'+id+'/SDSILLYTOKEN/'+token;
Ext.getStore("categoriesvaluestore").getProxy().setUrl(url);
Ext.getStore("categoriesvaluestore").load();
Ext.Viewport.remove(Ext.Viewport.getActiveItem(), true);
Ext.Viewport.add({ xtype: 'wordsview' });
}
When accessing your Store from your View or anywhere else, you can dinamically change the Url this way:
var stProxy = Ext.StoreMgr.get("myStore").getProxy();
stProxy.setUrl("http://the.new.url");
Ext.StoreMgr.set("myStore").setProxy(stProxy);
--
The particular problem in your scenario is that you may have to populate your list manually. If you want a List to include the result of calling the same Store with different URLs, I suggest to build a new local Store loading the content of all iterations. Then make the List "store" property be this global Store.

Populating Combobox from remote server

I have a combobox, i need to populate data from the server. In the server side i have the following data to be displayed.
PersonID
PersonFName
PersonLName
In the combobox, i need to display the text as PersonFName + PersonLName (Like James Smith- This is what it will display in the drop down) , and when a user selects a record, I need to display the corresponding PersonID (Like Person with PersonFName and PersonLName has the PersonID of 1) of that user.
I am unable to figure this out, here's my code
View :
{
xtype: 'combobox',
id: 'personcombo',
readOnly: false,
selectOnFocus: true,
forceSelection: true,
store: 'Person'
}
Store :
Ext.define('MyApp.store.PersonStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.Person'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
model: 'MyApp.model.Person',
proxy: {
type: 'ajax',
api: {
read: 'person.php',
create: 'person.php'
},
reader: {
type: 'array'
}
}
}, cfg)]);
}
});
Model :
Ext.define('MyApp.model.Person', {
extend: 'Ext.data.Model',
fields: [
{
name: 'PersonID'
},
{
name: 'PersonFName'
},
{
name: 'PersonLName'
}
]
});
I think your question is: how to display PersonFName + PersonLName in the combobox but keep the PersonID field as the value.
You should add a converted field which joins the first and last names in your data model and then make that one your combobox displayField config.
Though the other answer did bring up a good point that the defined store in your combo is Person but you are showing code for a store named PersonStore.
It would look something like this:
Model:
Ext.define('MyApp.model.Person', {
extend: 'Ext.data.Model',
fields: [
{
name: 'PersonID'
},
{
name: 'PersonFName'
},
{
name: 'PersonLName'
},
{
name: 'PersonName',
convert: function(value, record) {
return record.data.PersonFName + ' ' +
record.data.PersonLName;
}
}
]
});
Store:
// changed to "Person" instead of "PersonStore"
Ext.define('MyApp.store.Person', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.Person'
],
model: 'MyApp.model.Person',
proxy: {
type: 'ajax',
api: {
read: 'person.php',
create: 'person.php'
},
reader: 'array'
}
});
View:
{
xtype: 'combobox',
id: 'personcombo',
readOnly: false,
selectOnFocus: true,
forceSelection: true,
store: 'Person',
valueField: 'PersonID',
displayField: 'PersonName' // the converted field
}
Your combobox has 'Person' as the store, but I don't see you create a store called Person anywhere. Try store: Ext.create('MyApp.store.PersonStore', {autoLoad: true}).
You can also simplify your store:
Ext.define('MyApp.store.PersonStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.Person'
],
model: 'MyApp.model.Person',
proxy: {
type: 'ajax',
api: {
read: 'person.php',
create: 'person.php'
},
reader: 'array'
}
});