Что должно отвечать за загрузку хранилищ в приложении Ext JS 4 MVC?

Рассмотрим сложное приложение, в котором у вас есть настраиваемая логика фильтрации и различные режимы загрузки; отложенная загрузка при скрытии, отсутствие загрузки при скрытии, но загрузка при отображении и перезагрузка при изменении ваших пользовательских фильтров и т. д.

Какая часть приложения mvc должна отвечать за загрузку, и как это все подключить?


person Gaute Løken    schedule 24.08.2012    source источник


Ответы (2)


Я так и не нашел окончательного ответа на этот вопрос от Sencha, когда начинал работу с MVC, но я могу рассказать вам, что я успешно делал для нескольких приложений.

Я создаю и загружаю свои магазины в соответствии с тем, как они используются. Кажется, для меня это разделилось на три разные категории:

  1. Магазины, применимые ко всему приложению

  2. Хранилища, которые применяются ко всем экземплярам представления

  3. Магазины, привязанные к одному экземпляру представления

<сильный>1. Магазины, применимые ко всему приложению

Обычно у меня есть «основной» контроллер, который управляет структурой моего приложения, такими вещами, как навигация с помощью клавиатуры, главное меню и т. д.

Магазины, попадающие в первую категорию выше, помещаются в массив stores этого «основного» контроллера. Если эти магазины не зависят от другого магазина, я просто делаю их autoLoad: true и с ними покончено. Но в тех случаях, когда они зависят от данных другого хранилища, я добавляю прослушиватель в родительское хранилище, чтобы загрузить зависимое хранилище внутри родительского события onLoad.

Примером некоторых магазинов, попадающих в эту первую категорию, являются эталонные магазины, которые я использую в полях со списками по всему приложению, обычно во многих различных типах представлений. Обычно они настраиваются с помощью autoLoad: true, после чего я больше никогда не загружаю их для сеанса этого пользователя. Всякий раз, когда мне нужно поле со списком, которое использует хранилище ссылок, я могу настроить его следующим образом:

{
    xtype: 'combobox',
    allowBlank: false,
    forceSelection: true,
    store: Ext.getStore('SomeReferenceStore'),
    queryMode: 'local', // this makes sure the store doesn't reload
    valueField: 'id',
    displayField: 'name'
}

Чтобы привести пример двух магазинов, которые попадают в первую категорию, причем один зависит от другого:

В одном из моих приложений у меня есть динамическое количество пользовательских разрешений, когда пользователь входит в приложение, мне нужно было получить различные разрешения и изменить модель User, чтобы включить логическое поле для каждого из этих разных разрешений:

Ext.define('MyApp.controller.Main', {
    extend: 'Ext.app.Controller',

    models: [
        'User', 
        'Reference',
        // etc...
    ],

    stores: [
        'CurrentUser', 
        'PermissionRef', // this is "autoLoad: true"
        // etc...
    ],

    init: function() {
        var me = this;       

        // update the user model and load the user
        me.getPermissionRefStore().on('load', function(store, records) {
            var model = me.getUserModel(),
                fields = model.prototype.fields.getRange();

            // append the permissions onto the User model fields
            Ext.each(records, function(permission) {
                fields.push({
                    name: permission.get('name'), 
                    type: 'bool',
                });
            });

            // update the user model with the permission fields
            model.setFields(fields);

            // load the current user
            me.getCurrentUserStore().load();

            // other stuff...

        });

        // other stuff...

    }

});

При этом всякий раз, когда мне нужна ссылка на пользователя и какие разрешения у него есть, я просто вызываю:

var user = Ext.getStore('CurrentUser').first();

Иногда представление также будет зависеть от загружаемого хранилища. Например, пункты моего главного меню определяются таблицей базы данных, в этом случае я бы включил прослушиватель onLoad таким же образом (внутри функции init контроллера):

// create the menu once we know what menu items are available
me.getMenuStore().on('load', function(store) {
    me.getViewport().add(Ext.widget('mainpanel'));            
});

Сам MyApp.store.Menu будет настроен с autoLoad: true.

<сильный>2. Хранилища, которые применяются ко всем экземплярам представления

Я создаю и загружаю их так же, как и первую категорию, только помещаю их в массив stores конкретного контроллера view вместо массива stores контроллера «Main».

Тогда это та же основная концепция, некоторые autoLoad: true некоторые нет, если они зависят от данных другого хранилища.

Для тех, которые не являются autoLoad: true, они загружаются где-то внутри функции init контроллера или в результате запуска какого-либо события.

<сильный>3. Магазины, привязанные к одному экземпляру представления

Здесь я могу пойти против структуры MVC, но на самом деле нет лучшего места для хранилища, которое применяется к одному экземпляру представления, чем внутри самого представления.

В большинстве случаев я даже не помещаю эти хранилища в массив stores контроллера представления. Я просто создаю и загружаю их внутри функции представления initComponent. В результате этого, когда представление уничтожается, больше нет ссылки на хранилище, поэтому хранилище также будет уничтожено. Это помогает сократить ресурсы для магазинов, которые могут создаваться много раз.

Например, предположим, что у вас есть MyApp.view.UnicornWeightGrid, который расширяет gridpanel и показывает прогрессивный вес единорога с течением времени. Пользователь может открыть UnicornWeightGrid для всех единорогов в мире для сравнения и перекрестных ссылок. Будет столько разных экземпляров UnicornWeightStore, сколько экземпляров UnicornWeightGrid.

Представление может быть определено следующим образом:

Ext.define('MyApp.view.UnicornWeightGrid', {
    extend: 'Ext.grid.Panel',
    alias: 'widget.unicornweight',
    requires: [
        'MyApp.model.UnicornWeight'
    ],
    closable: true,    
    initComponent: function() {
        var me = this;

        me.store = Ext.create('Ext.data.Store', {
            model: 'MyApp.model.UnicornWeight',
            proxy: {
                type: 'ajax',
                url: 'unicorns/weight',
                extraParams: {
                    name: me.unicornName
                }
            }
        });

        me.store.load();
    });
});

Затем всякий раз, когда мы хотим получить другой UnicornWeightGrid, мы можем просто вызвать:

var grid = Ext.widget('unicornweight', {
    unicornName: someUnicornNameVariable
});

myTabPanel.add(grid);

Любые прослушиватели onLoad, которые мне нужны в хранилищах, определенных в представлении, я также прикрепляю внутри представления. Так что мне действительно не нужна ссылка где-либо еще.

С учетом всего сказанного, это ни в коем случае не единственный способ настроить свои магазины.

Я обнаружил, что это наиболее работоспособный способ последовательной обработки хранилищ при создании нескольких различных приложений ExtJS «MVC», но иногда я делаю это по-разному, в том числе в «особых» случаях.

Вы должны иметь в виду, что «MVC» — это довольно свободный шаблон проектирования, он определяется и реализуется по-разному почти в каждом фреймворке, который я использовал. Таким образом, вы можете делать то, что лучше всего подходит для вас.

person egerardus    schedule 24.08.2012
comment
Какой совершенно удивительный ответ. Большое тебе спасибо! :) Я имею в виду, что у меня были собственные мысли, но это просто очень всесторонне и хорошо сформулировано. Почему я не могу проголосовать больше одного раза? - person Gaute Løken; 24.08.2012

Вы должны поместить логику для загрузки хранилища внутри контроллера для сетки, которая будет отображать это хранилище. Я помещаю их в обработчик события afterrender.

person sha    schedule 24.08.2012