Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to filter Ext.List populated with hierarchical data from a store?
    primarykey
    data
    text
    <h3>Questions:</h3> <p>What is the recommended way to filter a Ext.List populated with hierarchical data from a store? I need to filter out child objects that belongs to a parent object I have selected to filter on. The childs, in this case <em>games</em> should then populate the list.</p> <h3>What I need</h3> <ul> <li>The Ext.List should be possible to filter by round, i.e. "Omgång 1", "Omgång 2" and so on. ("Omgång" = "Round" in Swedish) When selecting "Omgång 1" as filter the list should only display games from that round in the list. See JSON document below.</li> <li>The list should be grouped by date ("kickOff") and sorted by "gameId" ASC.</li> </ul> <h3>What I have done</h3> <ul> <li>Created an Ext.List populated with data retrived via an Ext.data.Store that gets data from a JSON document read via ReST proxy. </li> <li>The Ext.List reads its data from the store Rounds (see below). The problem is that I only see one game for round "Omgång 1" when there should be 8 games. </li> </ul> <p>This is what I have managed to achieve so far. The list is filtered using the buttons but only one of the list items are shown.</p> <p><img src="https://i.stack.imgur.com/vCsBr.png" alt="Example of the list and the filters."></p> <h3>EM.model.Round</h3> <p>The model for Round. It has a one-to-many relationship with Match.</p> <pre><code>Ext.define('EM.model.Round', { extend: 'Ext.data.Model', init: function() {}, config: { storeId: 'Rounds', fields: [ 'name', 'lockedDate', ], associations: { type: 'hasMany', model: 'EM.model.Match', primaryKey: 'gameId', name: 'matches', autoLoad: true, associationKey: 'games' } }, }); </code></pre> <h3>EM.model.Match</h3> <p>The model for Match. It belongs to Round.</p> <pre><code>Ext.define('EM.model.Match', { extend: 'Ext.data.Model', init: function() {}, config: { fields: [ { name: 'gameId', type: 'int' }, { name: 'firstTeam', type: 'string' }, { name: 'firstTeamClass', type: 'string', convert: function(value, record) { return util.convertFieldValueToLowerCase('firstTeam', record); } }, { name: 'secondTeam', type: 'string' }, { name: 'secondTeamClass', type: 'string', convert: function(value, record) { return util.convertFieldValueToLowerCase('secondTeam', record); } }, 'kickOff', { name: 'kickOffHour', convert: function(value, record) { var timestamp = new Date(util.convertUnixTimeToMilliseconds(record.get('kickOff'))); return Ext.Date.format(timestamp, 'H:i'); } }, { name: 'firstTeamGoals', type: 'int', defaultValue: 0 }, { name: 'secondTeamGoals', type: 'int', defaultValue: 0 }, { name: 'firstTeamGoalsBet', }, { name: 'secondTeamGoalsBet', }, 'points', { name: 'pointsEarned', convert: function(value, record) { var className = 'no-points-earned'; var points = record.get('points'); if (typeof points == 'undefined') { return ''; } if (points &gt; 0) { className = 'points-earned'; } return '&lt;div class="' + className + '"&gt;' + points + '&lt;/div&gt;' } }, ], associations: { type: 'belongsTo', model: 'EM.model.Round', name: 'round', autoLoad: true } } }); </code></pre> <h3>EM.store.Rounds</h3> <p>The store that reads the JSON document. This store is then used to populate the Ext.List.</p> <pre><code>Ext.define('EM.store.Rounds', { extend: 'Ext.data.Store', config: { model: 'EM.model.Round', storeId: 'Rounds', filters: [{ property: 'name', value: 'Round 1' }], /*grouper: { groupFn: function (item) { //var kickOff = new Date(util.convertUnixTimeToMilliseconds(item.get('kickOff'))); //return kickOff.format('d mmmm yyyy'); }, //sortProperty: 'kickOff' },*/ proxy: { type: 'rest', url : 'resources/json/matches.json', reader: { type: 'json', } }, autoLoad: true, } }); </code></pre> <h3>JSON document</h3> <p>This is the JSON document that is read by the proxy in <em>EM.store.Rounds</em>.</p> <pre><code>[ { "name": "Omgång 1", "lockedDate": 1325420111, "games": [ { "gameId": 1, "firstTeam": "Pol", "secondTeam": "Gre", "kickOff": 1339178400, "firstTeamGoals": 0, "secondTeamGoals": 3, "firstTeamGoalsBet": 0, "secondTeamGoalsBet": 3, "points": 3 }, { "gameId": 2, "firstTeam": "Rus", "secondTeam": "Cze", "kickOff": 1339188300, "firstTeamGoals": 4, "secondTeamGoals": 1, "firstTeamGoalsBet": 1, "secondTeamGoalsBet": 2, "points": 0 },{ "gameId": 3, "firstTeam": "Ned", "secondTeam": "Den", "kickOff": 1339264800, "firstTeamGoals": 2, "secondTeamGoals": 1, "firstTeamGoalsBet": 4, "secondTeamGoalsBet": 2, "points": 2 }, { "gameId": 4, "firstTeam": "Ger", "secondTeam": "Por", "firstTeamGoalsBet": 4, "secondTeamGoalsBet": 0, "kickOff": 1339274700 }, { "gameId": 5, "firstTeam": "Spa", "secondTeam": "Ita", "firstTeamGoalsBet": 3, "secondTeamGoalsBet": 2, "kickOff": 1339351200 }, { "gameId": 6, "firstTeam": "Irl", "secondTeam": "Cro", "kickOff": 1339361100 }, { "gameId": 7, "firstTeam": "Fra", "secondTeam": "Eng", "kickOff": 1339437600 }, { "gameId": 8, "firstTeam": "Ukr", "secondTeam": "Swe", "kickOff": 1339447500 } ] }, { "name": "Omgång 2", "games": [ { "gameId": 4, "firstTeam": "Gre", "secondTeam": "Cze", "kickOff": 1339524000 } ] }, { "name": "Omgång 3", "games": [ { "gameId": 4, "firstTeam": "Gre", "secondTeam": "Rus", "kickOff": 1339869600 } ] }, { "name": "Kvart", "games": [ { "gameId": 4, "firstTeam": "1A", "secondTeam": "2B", "kickOff": 1340311500 } ] }, { "name": "Semi", "games": [ { "gameId": 4, "firstTeam": "#25", "secondTeam": "#27", "kickOff": 1340829900 } ] }, { "name": "Final", "games": [ { "gameId": 4, "firstTeam": "#29", "secondTeam": "#30", "kickOff": 1341175500 } ] } ] </code></pre> <h3>EM.view.MatchList</h3> <p>The list view that displays the list of matches.</p> <pre><code>Ext.define('EM.view.MatchList', { extend: 'Ext.List', xtype: 'matchlist', requires: [ 'Ext.TitleBar', 'EM.store.Rounds' ], config: { id: 'match-list', store: 'Rounds', //grouped: true, scrollable: false, items: [ { xtype: 'titlebar', scrollable: { direction: 'horizontal', directionLock: true }, items: [ { xtype: 'button', text: 'Omgång 1', handler: function() { var sto = Ext.getStore('Rounds'); sto.clearFilter(); sto.filter('name', 'Omgång 1'); console.log(sto); } }, { xtype: 'button', text: 'Omgång 2', handler: function() { var sto = Ext.getStore('Rounds'); sto.clearFilter(); sto.filter('name', 'Omgång 2'); } }, { xtype: 'button', text: 'Omgång 3', handler: function() { var sto = Ext.getStore('Rounds'); sto.clearFilter(); sto.filter('name', 'Omgång 3'); } }, { xtype: 'button', text: 'Kvart', handler: function() { var sto = Ext.getStore('Rounds'); sto.clearFilter(); sto.filter('name', 'Kvart'); } }, { xtype: 'button', text: 'Semi', handler: function() { var sto = Ext.getStore('Rounds'); sto.clearFilter(); sto.filter('name', 'Semi'); } }, { xtype: 'button', text: 'Final', handler: function() { var sto = Ext.getStore('Rounds'); sto.clearFilter(); sto.filter('name', 'Final'); } } ], }, { xtype: 'panel', html: 'Senast uppdaterad: Idag kl 20:12' } ], itemTpl: [ '&lt;div class="match-meta-data"&gt;', '&lt;tpl for="matches"&gt;', '&lt;div class="team-wrapper home-team"&gt;{firstTeam} &lt;div class="flag {firstTeamClass}"&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt; &lt;span class="goals-scored"&gt;{firstTeamGoals}&lt;/span&gt;&lt;/div&gt;', '&lt;div class="kick-off-time"&gt;{kickOffHour}&lt;/div&gt;', '&lt;div class="team-wrapper away-team"&gt;&lt;span class="goals-scored"&gt;{secondTeamGoals}&lt;/span&gt; &lt;div class="flag {secondTeamClass}"&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt; {secondTeam}&lt;/div&gt;', '&lt;div class="bet-meta-data"&gt;', '&lt;img class="user-icon" src="resources/images/user-22x26.png" /&gt;', '&lt;div class="home-team goals-bet"&gt;{firstTeamGoalsBet}&lt;/div&gt;', '&lt;div class="away-team goals-bet"&gt;{secondTeamGoalsBet}&lt;/div&gt;', '{pointsEarned}', '&lt;/div&gt;', '&lt;/tpl&gt;', '&lt;/div&gt;', ].join('') }, }); </code></pre> <p>This is my first Sencha Touch app, so feel free to point out any bad practices that you see in the code. Could someone please provide an example of how to achieve what I'm aiming for? I have spent a lot of time trying to figure this one out. </p> <p>The full project can be downloaded from GitHub at <a href="https://github.com/eriktoyra/EM-Tipset" rel="nofollow noreferrer">https://github.com/eriktoyra/EM-Tipset</a>. Latest branch is _filter-match-list.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload