2

问题:

过滤填充了来自商店的分层数据的 Ext.List 的推荐方法是什么?我需要过滤掉属于我选择过滤的父对象的子对象。孩子们,在这种情况下,游戏应该填充列表。

我需要的

  • Ext.List 应该可以按轮次过滤,即“Omgång 1”、“Omgång 2”等。("Omgång" = "Round" in Swedish) When selecting "Omgång 1" as filter the list should only display games from that round in the list. 请参阅下面的 JSON 文档。
  • 该列表应按日期(“kickOff”)分组并按“gameId”ASC 排序。

我做了什么

  • 创建了一个 Ext.List,其中填充了通过 Ext.data.Store 检索的数据,该数据从通过 ReST 代理读取的 JSON 文档中获取数据。
  • Ext.List 从存储 Rounds 中读取其数据(见下文)。问题是我只看到一轮“Omgång 1”的一场比赛,而应该有 8 场比赛。

这是我迄今为止所取得的成就。使用按钮过滤列表,但仅显示其中一个列表项。

列表和过滤器的示例。

EM.model.Round

圆形的模型。它与 Match 具有一对多的关系。

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'
    }   
},
});

EM.model.Match

匹配的模型。它属于圆形。

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 > 0) {
                    className = 'points-earned';
                }

                return '<div class="' + className + '">' + points + '</div>'
            }
        },
    ],

    associations: {
        type: 'belongsTo',
        model: 'EM.model.Round',
        name: 'round',
        autoLoad: true
    }

}
});

EM.store.Rounds

读取 JSON 文档的存储。然后使用该存储来填充 Ext.List。

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,
}
});

JSON 文件

这是EM.store.Rounds中的代理读取的 JSON 文档。

[
{   
    "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
        }
     ]
}
]

EM.view.MatchList

显示匹配列表的列表视图。

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: [

        '<div class="match-meta-data">',
        '<tpl for="matches">',          
            '<div class="team-wrapper home-team">{firstTeam} <div class="flag {firstTeamClass}"><span></span></div> <span class="goals-scored">{firstTeamGoals}</span></div>',
            '<div class="kick-off-time">{kickOffHour}</div>',
            '<div class="team-wrapper away-team"><span class="goals-scored">{secondTeamGoals}</span> <div class="flag {secondTeamClass}"><span></span></div> {secondTeam}</div>',
            '<div class="bet-meta-data">',
                '<img class="user-icon" src="resources/images/user-22x26.png" />',
                '<div class="home-team goals-bet">{firstTeamGoalsBet}</div>',
                '<div class="away-team goals-bet">{secondTeamGoalsBet}</div>',
                '{pointsEarned}',   
            '</div>',
        '</tpl>',
        '</div>',

        ].join('')
    },

});

这是我的第一个 Sencha Touch 应用程序,因此请随时指出您在代码中看到的任何不良做法。有人可以提供一个如何实现我的目标的例子吗?我花了很多时间试图弄清楚这一点。

完整的项目可以从 GitHub 下载,地址为https://github.com/eriktoyra/EM-Tipset。最新的分支是 _filter-match-list。

4

2 回答 2

0

这确实是两个问题。我不知道为什么您的整个商店似乎没有在列表视图中呈现;一些步进和暂停可能会更清楚地说明这一点。如果您在某处托管了演示,我很乐意查看它。

关于您的多轮过滤问题,我现在可以想到两件事:

  • 据我所知,filter对存储执行操作会导致它“丢失”数据,即丢弃所有与过滤器不匹配的数据(而不是对访问者隐藏它)。如果您在同一个服务器调用中将所有回合加载到一个商店中,我不确定过滤是否适合您。我可能错了,但我只是尝试从 Javascript 控制台过滤我的一个应用程序中的商店;当我应用与任何商品都不匹配的过滤器时,商店清空了。基于此,过滤可能不是最好的选择。

  • 为每个回合创建一个单独listview的回合,每个回合都使用相同的通用回合商店。使用itemTplconfig 和 anXTemplate来决定哪些匹配项应该进入每个列表。根据需要,使用 Omgång 按钮从视口中换出这些列表。

在更好地理解您的问题和代码后更新答案

于 2012-04-10T15:09:50.630 回答
0

我设法通过使用类似于我所拥有的实际测试场景的测试场景找到了解决此问题的方法。

解决方案

我所做的是:

  1. 让 Division 模型处理代理并从match.json读取数据,而不是让 Division 存储读取数据。
  2. 设置 Division 和 Team 模型之间的关系,以便它们相互了解。
  3. 设置两个商店。一个用于部门,一个用于团队。加载 Division 存储时,我使用回调来使用 Division 存储中的 Team 数据填充 Team 存储。
  4. 然后,我使用 Team 存储填充列表,其中包含 Team 对象,这些对象现在知道它们对 Division 模型/存储的引用。
  5. 实际过滤是通过在列表中查找每个 Team 项目的 Division 对象并将 Division 的name属性与过滤器提供的属性进行比较来完成的。

下面提供了完整的解决方案,也可以在GitHub上找到。

如果其他人应该找到更好的解决方案或指出一些改进,我会在几天内保持这个问题没有答案。

    /**
     * @description The main purpose of this mockup is to test how to filter a list using hierarchical data. The code is adapted from the example 
     * "Filtering data in an Ext.List component in Sencha Touch 2" by Peter deHaan.  
     * @see <a href="http://senchaexamples.com/2012/03/15/filtering-data-in-an-ext-list-component-in-sencha-touch-2/">Filtering data in an Ext.List component in Sencha Touch 2</a>.
     * @author <a href="mailto:erik.toyra[at]gmail.com">Erik Töyrä</a>      
     */
    Ext.application({
        launch: function () {
            /**
             * Division model
             */
            Ext.define("Division", {
                extend: 'Ext.data.Model',
                config: {
                    fields: [
                        'division'
                    ],
                    // Setup a hasMany relations between Division and Team
                    hasMany: {model: 'Team', name: 'teams'},

                    // Load data from teams.json into the Division model
                    proxy: {
                        type: 'rest',
                        url : 'teams.json',
                        reader: {
                            type: 'json'
                        }
                    }
                }
            });

            /**
             * Team model
             */
            Ext.define("Team", {
                extend: 'Ext.data.Model',
                config: {
                    fields: [
                        'name', 'league'
                    ],
                    // Setup a belongsTo relationship between Team and Division
                    belongsTo: {model: 'Division'},
                }
            });                

            /**
             * Division store
             */
            var divisionStore = Ext.create('Ext.data.Store', {
                model: "Division",
                storeId: 'divisionStore',
            });

            /**
             * Team store
             */
            var teamStore = Ext.create('Ext.data.Store', {
                model: "Team",
                storeId: 'teamStore', // This is the store we will reference in our Ext.list below.
                fields: ['division', 'leage', 'name'],
            });

            /**
             * Load the Division store which holds all of the data read from teams.json. 
             * After the data has been loaded we add the team data to the teamStore.
             */
            divisionStore.load({
                callback: function() {
                    // Loop through each division and retrieve the all teams that resides as 
                    // childs to the division. Then we add each team to the teamStore.
                    divisionStore.each(function(division) {
                        division.teams().each(function(team) {
                            teamStore.add(team);
                        });
                    });
                }
            });

            /**
             * Create the list that should be filtered by Division and display a filtered list with Team objects.
             */
            Ext.create('Ext.List', {
                fullscreen: true,

                items: [{
                    xtype: 'titlebar',
                    docked: 'top',
                    ui: 'neutral',

                    items: [{
                        text: 'West only',
                        handler: function () {
                            return util.doFilter('West');
                        } // handler
                    }, {
                        text: 'Central only',
                        handler: function () {
                            return util.doFilter('Central');
                        } // handler
                    }, {
                        text: 'East only',
                        handler: function () {
                            return util.doFilter('East');                               
                        } // handler
                    }, {
                        text: 'Clear filters',
                        ui: 'decline',
                        align: 'right',
                        handler: function () {
                            Ext.getStore('teamStore').clearFilter();
                        } // handler
                    }
                    ] // items (toolbar)
                }], // items (list)
                store: 'teamStore',
                itemTpl: '{name}, {league}',
            }); // create()


            /**
             * Utility functions
             */
            var util = (function() {
                var util = {};

                /**
                 * Filter the teamStore by the passed in Division name.
                 */
                util.doFilter = function(filterOption) {
                    var store = Ext.getStore('teamStore');

                    // Clear all existing filters first...
                    store.clearFilter();

                    // ... then apply the selected filter
                    store.filterBy(function(record, id) {
                            return record.getDivision().get('division') == filterOption;
                        }, this);
                }

                return util;
            })();
        } // launch
    }); // application()

JSON数据

[
{
    division: 'East',
    teams: [
        {
            name: 'New York Yankees',
            league: 'AL',
        }, {
            name: 'Tampa Bay',
            league: 'AL',
        }, {
            name: 'Boston',
            league: 'AL',
        }, {
            name: 'Toronto',
            league: 'AL',
        }, {
            name: 'Baltimore',
            league: 'AL',
        }
    ]
},
{
    division: 'Central',
    teams: [
        {
            name: 'Detroit',
            league: 'AL',

        }, {
            name: 'Cleveland',
            league: 'AL',
        }, {
            name: 'Chicago White Sox',
            league: 'AL',
        }, {
            name: 'Kansas City',
            league: 'AL',
        }, {
            name: 'Minnesota',
            league: 'AL',
        }                            
    ]
},
{
    division: 'West',
    teams: [
    {
            name: 'Texas',
            league: 'AL',
        }, {
            name: 'Los Angeles Angels',
            league: 'AL',
        }, {
            name: 'Oakland',
            league: 'AL',
        }, {
            name: 'Seattle',
            league: 'AL',
        }
    ]
}
]
于 2012-04-10T21:52:37.150 回答