I'm sure there is a better way to post this information, but the is the best way I know of for now... so, buckle up and hang on for an extremely long post.
I needed to use a nested list, based on XML data, but could not get it to work with Sencha Touch's nested list, so I rolled my own. Please improve it in any way you can.
The basic ingredients for this recipe are:
- an xml file
- a navigation view
- one high level view (used as default in navigation view)
- several lower level views
- one high level store
- several 'temporary' stores
- several associated models
- several 'temporary store' models
For the sake of simplicity, I did not use any controllers. Instead, I just used listeners.
Here are the files. There are 15 of them to make a three-tiered nested list.
app.js
HTML Code:
Ext.application({
name: 'nestedXMLexample',
requires: [
'Ext.data.Store'
],
views: [
'TheNavigationView',
'HigherLevelListView',
'LowestTempListView',
'MiddleTempListView'
],
models: [
'TopLevelModel',
'LowestLevelModel',
'MiddleLevelModel',
'MiddleTemporaryStoreModel',
'LowestTemporaryStoreModel'
],
stores: [
'AssociatedModelsStore',
'MiddleTemporaryStore',
'LowestTemporaryStore'
],
launch: function() {
// Initialize the main view
Ext.Viewport.add(Ext.create('nestedXMLexample.view.TheNavigationView'));
},
});
index.html
HTML Code:
<!DOCTYPE HTML>
<html manifest="" lang="en-US">
<head>
<meta charset="UTF-8">
<title>nestedXMLexample</title>
<style type="text/css">
/**
* Example of an initial loading indicator.
* It is recommended to keep this as minimal as possible to provide instant feedback
* while other resources are still being loaded for the first time
*/
html, body {
height: 100%;
background-color: #1985D0
}
#appLoadingIndicator {
position: absolute;
top: 50%;
margin-top: -15px;
text-align: center;
width: 100%;
height: 30px;
-webkit-animation-name: appLoadingIndicator;
-webkit-animation-duration: 0.5s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: linear;
}
#appLoadingIndicator > * {
background-color: #FFFFFF;
display: inline-block;
height: 30px;
-webkit-border-radius: 15px;
margin: 0 5px;
width: 30px;
opacity: 0.8;
}
@-webkit-keyframes appLoadingIndicator{
0% {
opacity: 0.8
}
50% {
opacity: 0
}
100% {
opacity: 0.8
}
}
</style>
<!-- The line below must be kept intact for Sencha Command to build your application -->
<script id="microloader" type="text/javascript" src="sdk/microloader/development.js"></script>
</head>
<body>
<div id="appLoadingIndicator">
<div></div>
<div></div>
<div></div>
</div></body>
</html>
structuredSampleXML.xml
HTML Code:
<TopAlphaGrouper>
<TopAlphaItem TopAlphaItemAttributeOne="A">
<RomanGrouper>
<RomanItem RomanItemAttributeOne="I">
<LowerAlphaGrouper>
<LowerAlphaItem LowerAlphaAttribute="a"/>
</LowerAlphaGrouper>
</RomanItem>
<RomanItem RomanItemAttributeOne="II">
<LowerAlphaGrouper>
<LowerAlphaItem LowerAlphaAttribute="a"/>
<LowerAlphaItem LowerAlphaAttribute="b"/>
</LowerAlphaGrouper>
</RomanItem>
<RomanItem RomanItemAttributeOne="III">
<LowerAlphaGrouper>
<LowerAlphaItem LowerAlphaAttribute="a"/>
<LowerAlphaItem LowerAlphaAttribute="b"/>
<LowerAlphaItem LowerAlphaAttribute="c"/>
</LowerAlphaGrouper>
</RomanItem>
<RomanItem RomanItemAttributeOne="IV">
<LowerAlphaGrouper>
<LowerAlphaItem LowerAlphaAttribute="a"/>
<LowerAlphaItem LowerAlphaAttribute="b"/>
<LowerAlphaItem LowerAlphaAttribute="c"/>
<LowerAlphaItem LowerAlphaAttribute="d"/>
</LowerAlphaGrouper>
</RomanItem>
</RomanGrouper>
</TopAlphaItem>
<TopAlphaItem TopAlphaItemAttributeOne="B">
<RomanGrouper>
<RomanItem RomanItemAttributeOne="X">
<LowerAlphaGrouper>
<LowerAlphaItem LowerAlphaAttribute="z"/>
<LowerAlphaItem LowerAlphaAttribute="y"/>
<LowerAlphaItem LowerAlphaAttribute="x"/>
<LowerAlphaItem LowerAlphaAttribute="j"/>
</LowerAlphaGrouper>
</RomanItem>
<RomanItem RomanItemAttributeOne="II">
<LowerAlphaGrouper>
<LowerAlphaItem LowerAlphaAttribute="a"/>
<LowerAlphaItem LowerAlphaAttribute="b"/>
<LowerAlphaItem LowerAlphaAttribute="c"/>
<LowerAlphaItem LowerAlphaAttribute="d"/>
</LowerAlphaGrouper>
</RomanItem>
</RomanGrouper>
</TopAlphaItem>
<TopAlphaItem TopAlphaItemAttributeOne="C"/>
<TopAlphaItem TopAlphaItemAttributeOne="D">
<RomanGrouper>
<RomanItem RomanItemAttributeOne="XLII">
<LowerAlphaGrouper>
<LowerAlphaItem LowerAlphaAttribute="alpha"/>
<LowerAlphaItem LowerAlphaAttribute="beta"/>
<LowerAlphaItem LowerAlphaAttribute="gamma"/>
<LowerAlphaItem LowerAlphaAttribute="delta"/>
</LowerAlphaGrouper>
</RomanItem>
<RomanItem RomanItemAttributeOne="MMXII">
<LowerAlphaGrouper>
<LowerAlphaItem LowerAlphaAttribute="This"/>
<LowerAlphaItem LowerAlphaAttribute="is"/>
<LowerAlphaItem LowerAlphaAttribute="the"/>
<LowerAlphaItem LowerAlphaAttribute="current"/>
<LowerAlphaItem LowerAlphaAttribute="year"/>
</LowerAlphaGrouper>
</RomanItem>
</RomanGrouper>
</TopAlphaItem>
<TopAlphaItem TopAlphaItemAttributeOne="E"/>
</TopAlphaGrouper>
TheNavigationView.js
HTML Code:
Ext.define('nestedXMLexample.view.TheNavigationView', {
extend: 'Ext.navigation.View',
id: 'theNavigationViewId',
xtype: 'theNavigationViewXtype',
title: 'Navigation View Title',
requires: [
'nestedXMLexample.view.HigherLevelListView',
'nestedXMLexample.view.MiddleTempListView',
'nestedXMLexample.view.LowestTempListView'
],
config: {
items: [{
xtype:'higherLevelListXtype',
}],
listeners: {
back: function(){
console.log('back tapped');
console.log(this.getActiveItem().getStore());
var tempStore=Ext.getStore('middleTemporaryStoreId');
var lowTempStore=Ext.getStore('lowestMiddleTemporaryStoreId')
if(this.getActiveItem().getStore()==tempStore){
lowTempStore.setData("");
}
else{
tempStore.setData("");
}
console.log('store emptied');
}
}
}
});
HigherLevelListView.js
HTML Code:
Ext.define("nestedXMLexample.view.HigherLevelListView", {
extend: 'Ext.List',
xtype: 'higherLevelListXtype',
config: {
fullscreen: true,
store: 'associatedModelsStoreId',
scrollable: true,
itemTpl: new Ext.XTemplate(
'<tpl for==".">
'<tpl if="TopAlphaItemAttributeOne==\'A\'"><div>{TopAlphaItemAttributeOne}</div><div style="color:red"><small> {TopLevelListOfChildren}</small></div></tpl>'+
'<tpl if="TopAlphaItemAttributeOne!=\'A\'"><div>{TopAlphaItemAttributeOne}</div><div style="color:green"><small> {TopLevelListOfChildren}</small></div></tpl>'+
'</tpl>'
),
listeners: {
itemtap: function(list, index, element, record){
console.log('item tapped in main view');
var assocModelStore=Ext.getStore('associatedModelsStoreId');
var tempStore=Ext.getStore('middleTemporaryStoreId');
assocModelStore.each(function(placeHolderForTopAlphaItem){
var listOfChildren="";
if(placeHolderForTopAlphaItem.get('TopAlphaItemAttributeOne')==record.get('TopAlphaItemAttributeOne')){
placeHolderForTopAlphaItem.RomanGrouper().each(function(RomanItem){
RomanItem.LowerAlphaGrouper().each(function(LowerAlphaItem){
listOfChildren+=LowerAlphaItem.get('LowerAlphaAttribute')+" ";
})
if(listOfChildren!=""){
listOfChildren=listOfChildren.slice(0,-1);
}
tempStore.add({
parentItemReference: placeHolderForTopAlphaItem.get('TopAlphaItemAttributeOne'),
tempFieldOne: RomanItem.get('RomanItemAttributeOne'),
listOfChildItems: listOfChildren
});
console.log(placeHolderForTopAlphaItem.get('TopAlphaItemAttributeOne')+
" "+
RomanItem.get('RomanItemAttributeOne')+
" "+
listOfChildren);
listOfChildren="";
});
}
});
console.log(record.get('TopLevelListOfChildren'));
if(record.get('TopLevelListOfChildren')!=""){
this.getParent().push({
xtype: 'middleTempListViewXtype',
title: 'temp List'
});
}
}
}
}
});
MiddleTempListView.js
HTML Code:
Ext.define("nestedXMLexample.view.MiddleTempListView", {
extend: 'Ext.List',
xtype: 'middleTempListViewXtype',
config: {
fullscreen: true,
store: 'middleTemporaryStoreId',
scrollable: true,
itemTpl: new Ext.XTemplate(
'<div>{tempFieldOne}</div><div style="color:orange"><small>{listOfChildItems}</small></div>'
),
listeners: {
itemtap: function(list, index, element, record){
console.log('item tapped in MiddleTempListView');
console.log(element);
console.log(record);
var assocModelStore=Ext.getStore('associatedModelsStoreId');
var lowestTempStore=Ext.getStore('lowestMiddleTemporaryStoreId');
assocModelStore.each(function(placeHolderForTopAlphaItem){
placeHolderForTopAlphaItem.RomanGrouper().each(function(RomanItem){
RomanItem.LowerAlphaGrouper().each(function(LowerAlphaItem){
if(
placeHolderForTopAlphaItem.get('TopAlphaItemAttributeOne')
==
record.get('parentItemReference')
&&
RomanItem.get('RomanItemAttributeOne')
==
record.get('tempFieldOne')){
lowestTempStore.add({
grandparentItemReference: record.get('parentItemReference'),
parentItemReference: record.get('tempFieldOne'),
lowestTempFieldOne: LowerAlphaItem.get('LowerAlphaAttribute')
})
console.log(LowerAlphaItem.get('LowerAlphaAttribute'));
}
})
})
})
lowestTempStore.each(function(s){
console.log(s.get('grandparentItemReference'));
})
this.getParent().push({
xtype: 'lowestMiddleTempListViewXtype',
title: 'did it'
})
}
}
}
});
LowestLevelTempListView.js
HTML Code:
Ext.define("nestedXMLexample.view.LowestTempListView", {
extend: 'Ext.List',
xtype: 'lowestMiddleTempListViewXtype',
config: {
fullscreen: true,
store: 'lowestMiddleTemporaryStoreId',
scrollable: true,
itemTpl: new Ext.XTemplate(
'{lowestTempFieldOne}'
)
}
});
TopLevelModel.js
HTML Code:
Ext.define('nestedXMLexample.model.TopLevelModel', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'TopAlphaItemAttributeOne', mapping:'@TopAlphaItemAttributeOne'},
'TopLevelListOfChildren'
],
hasMany: [
{model: 'nestedXMLexample.model.MiddleLevelModel', name: 'RomanGrouper', associationKey: 'RomanGrouper'}
]
}
});
MiddleLevelModel.js
HTML Code:
Ext.define('nestedXMLexample.model.MiddleLevelModel', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'RomanItemAttributeOne', mapping:'@RomanItemAttributeOne'},
],
hasMany:[
{model: 'nestedXMLexample.model.LowestLevelModel', name: 'LowerAlphaGrouper', associationKey: 'LowerAlphaGrouper'}
],
belongsTo: 'nestedXMLexample.model.TopLevelModel',
proxy: {
reader: {
type: 'xml',
record: 'RomanItem'
}
}
}
});
LowestLevelModel.js
HTML Code:
Ext.define('nestedXMLexample.model.LowestLevelModel', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'LowerAlphaAttribute', mapping:'@LowerAlphaAttribute'}
],
belongsTo: 'nestedXMLexample.model.MiddleLevelModel',
proxy: {
reader: {
type: 'xml',
record: 'LowerAlphaItem'
}
}
}
});
MiddleTemporaryStoreModel.js
HTML Code:
Ext.define('nestedXMLexample.model.MiddleTemporaryStoreModel', {
extend: 'Ext.data.Model',
config: {
fields: [
'parentItemReference',
{name: 'tempFieldOne', type: 'string'},
'listOfChildItems'
]
}
});
LowestTemporaryStoreModel.js
HTML Code:
Ext.define('nestedXMLexample.model.LowestTemporaryStoreModel', {
extend: 'Ext.data.Model',
config: {
fields: [
'grandparentItemReference',
'parentItemReference',
{name: 'lowestTempFieldOne', type: 'string'}
]
}
});
AssociatedModelsStore.js
HTML Code:
Ext.define('nestedXMLexample.store.AssociatedModelsStore',{
extend: 'Ext.data.Store',
config: {
storeId: 'associatedModelsStoreId',
model: 'nestedXMLexample.model.TopLevelModel',
autoLoad: true,
defaultrootProperty: 'TopAlphaItem',
proxy: {
type: 'ajax',
url : 'structuredSampleXML.xml',
reader: {
type: 'xml',
record: 'TopAlphaItem'
}
},
listeners:{
load: (function(placeHolder){
placeHolder.each(function(placeHolderForTopAlphaItem){
var collectorString="";
placeHolderForTopAlphaItem.RomanGrouper().each(function(RomanItem){
collectorString+=RomanItem.get('RomanItemAttributeOne')+" ";
});
if(collectorString!=""){
collectorString=collectorString.slice(0,-1);
}
placeHolderForTopAlphaItem.set('TopLevelListOfChildren', collectorString);
});
})
}
}
});
MiddleTemporaryStore.js
HTML Code:
Ext.define('nestedXMLexample.store.MiddleTemporaryStore',{
extend: 'Ext.data.Store',
config: {
storeId: 'middleTemporaryStoreId',
model: 'nestedXMLexample.model.MiddleTemporaryStoreModel',
}
});
LowestTemporaryStore.js
HTML Code:
Ext.define('nestedXMLexample.store.LowestTemporaryStore',{
extend: 'Ext.data.Store',
config: {
storeId: 'lowestMiddleTemporaryStoreId',
model: 'nestedXMLexample.model.LowestTemporaryStoreModel',
}
});