2

質問:

ストアからの階層データが取り込まれた Ext.List をフィルタリングするための推奨される方法は何ですか? フィルターで選択した親オブジェクトに属する子オブジェクトを除外する必要があります。子 (この場合はゲーム)がリストに入力されます。

必要なもの

  • Ext.List は、「Omgång 1」、「Omgång 2」などのラウンドでフィルタリングできる必要があります。(「Omgång」 = スウェーデン語で「ラウンド」) フィルタとして「Omgång 1」を選択すると、リストにはそのラウンドのゲームのみが表示されます。以下の JSON ドキュメントを参照してください。
  • リストは日付 (「kickOff」) でグループ化し、「gameId」ASC で並べ替える必要があります。

私がやった事

  • ReST プロキシ経由で読み取った JSON ドキュメントからデータを取得する Ext.data.Store 経由で取得したデータが入力された Ext.List を作成しました。
  • Ext.List は、ストア Rounds からデータを読み取ります (以下を参照)。問題は、ラウンド「Omgång 1」で 8 つのゲームがあるはずなのに、1 つのゲームしか表示されないことです。

これは私がこれまでに達成したことです。リストはボタンを使用してフィルタリングされますが、リスト項目の 1 つだけが表示されます。

リストとフィルターの例。

EM.model.Round

ラウンド用モデル。Match とは 1 対多の関係にあります。

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 アプリなので、コードに見られる悪い慣行があれば遠慮なく指摘してください。誰かが私が目指していることを達成する方法の例を教えてください。私はこれを理解しようと多くの時間を費やしました。

完全なプロジェクトは、 https://github.com/eriktoyra/EM-Tipsetの GitHub からダウンロードできます。最新のブランチは _filter-match-list です。

4

2 に答える 2

0

実際のシナリオに似たテストシナリオを使用して、この問題の解決策を見つけることができました。

解決

私がしたことは:

  1. Divisionストアにデータを読み取らせる代わりに、Divisionモデルにプロキシを処理させ、match.jsonからデータを読み取らせます。
  2. 部門モデルとチームモデルの間に関係を設定して、お互いを認識できるようにします。
  3. 2つのストアをセットアップします。1つは部門用、もう1つはチーム用です。ディビジョンストアをロードするときに、コールバックを使用して、ディビジョンストアからのチームデータをチームストアに入力しました。
  4. 次に、リストにTeamストアを入力しました。このストアには、Divisionモデル/ストアへの参照を認識しているTeamオブジェクトが含まれています。
  5. 実際のフィルタリングは、リスト内の各チームアイテムの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 に答える
0

これらは実際には2つの問題です。ストア全体がリスト ビューにレンダリングされていないように見える理由がわかりません。いくつかのステップと一時停止により、それがさらに明らかになる可能性があります。どこかでホストされているデモがあれば、喜んで見てみたいです。

複数ラウンド フィルタリングの問題に関して、現在 2 つのことが考えられます。

  • 私が知る限りfilter、ストアでアクションを実行すると、データが「失われ」ます。つまり、フィルターに一致しないすべてのデータが破棄されます (アクセサーから非表示にするのではなく)。同じサーバー呼び出しですべてのラウンドを 1 つのストアにロードしている場合、フィルタリングが正しいことかどうかわかりません。これについては間違っているかもしれませんが、Javascript コンソールからアプリケーションの 1 つでストアをフィルタリングしようとしました。どのアイテムとも一致しないフィルターを適用すると、ストアが空になりました。これに基づいて、おそらくフィルタリングはここで行うのが最善の方法ではありません.

  • listviewラウンドごとに個別に作成し、それぞれが同じ共通のラウンド ストアを使用します。itemTplconfig と anを使用して、XTemplateどの一致を各リストに入れるかを決定します。必要に応じて、Omgång ボタンを使用して、ビューポートからこれらのリストを入れ替えます。

問題とコードをよりよく理解した後、回答を更新してください

于 2012-04-10T15:09:50.630 に答える