Динамически управлять Ext.app.Application.controllers

В настоящий момент наша команда оценивает возможность конвертации большого корпоративного веб-приложения (своего рода ERP-систему, более 600 уникальных экранов) с использованием ExtJS для интерфейса. Приложение было построено на нашем открывшемся исходном eludia двигателе

Наш движок требует определения модели (он изменяет базу данных при редактировании определения), имеет какой-то контроллер (Модули содержания) и Презентация (Модули презентации с кодом, который генерирует фактический js + html mix)

Как и некоторые люди из этой, наша команда сталкивается с проблемой:

Мы хотели бы иметь модель и представление на стороне сервера и просто отправлять JSON-данные в интерфейс

В настоящее время разработчики ядра eludia (= моя команда, мы поддерживаем как это приложение, так и eludia) сделали несколько шагов к движению морфинга, чтобы использовать ExtJS как интерфейс

Моя команда рассматривает:

  • продолжить использование старых модулей контента в качестве кода на стороне сервера
  • создание файлов модели для ExtJS "на лету" с использованием определения модели на стороне сервера,
  • преобразование модулей презентации в клиентские модули просмотра ExtJS и запись клиентских контроллеров для каждого экрана Но теперь есть еще одна проблема: ExtJS требует перечислить все контроллеры в Ext.app.Application Каждый раз, когда человек пишет новый/преобразует экран из старого движка, он должен добавить его в этот список

Можно ли генерировать динамические переменные Ext.app.Application.controllers?

Поэтому эти вопросы, упорядоченные по нечеткости:

  • Можете ли вы назвать достаточно большое (более 600 экранов, предпочтительное приложение с открытым исходным кодом) MVC/non MVC, которое использует ExtJS как front-end?
  • Правильно ли мы движемся?

UPDATE

Я должен попытаться сузить вопрос

Не нужно загружать все контроллеры сразу во время запуска приложения?

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

  • создать один контроллер js для открытого экрана.
  • добавить новые в Ext.app.Application.controllers когда пользователь что-то делает (нажимает ссылку, кнопку и т.д.): когда нужен новый экран

Ответ 1

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

//let say you need to use controller User:
var controller = ControllerManager.get('User');//I believe you have some controller manager, similar to Sencha Ext.ControllerManager
if(controller){
//use it here
}
else {
  loadScript([url of your controller script], controllerLoaded);
}
...
function controllerLoaded(){
//create controller instance here if needed and use it then
}
...
function loadScript(url, callback){

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState){  //IE
        script.onreadystatechange = function(){
            if (script.readyState == "loaded" ||
                    script.readyState == "complete"){
                script.onreadystatechange = null;
                callback();
            }
        };
    } else {  //Others
        script.onload = function(){
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

UPDATE Чтобы интегрировать новый контроллер в уже запущенный Ext.app.Application, вам нужно расширить Ext.app.Application и добавить следующий метод:

addController: function(name){
  //at this point your controller .js file should be already loaded into the DOM  
  var c = this.getController(name); //controller will be created automatically by name in this getter 
  //perform the same initialization steps as it would have during normal ExtJs process
  c.init(this);
  с.onLaunch(this);
}

Btw вместо использования настраиваемого метода для загрузки файла javascript динамически вы можете использовать встроенный метод ExtJs Ext.Loader:

/**
         * Load a script file, supports both asynchronous and synchronous approaches
         *
         * @param {String} url
         * @param {Function} onLoad
         * @param {Object} scope
         * @param {Boolean} synchronous
         * @private
         */
        loadScriptFile: function(url, onLoad, onError, scope, synchronous)

Ответ 2

Лучше всего зависеть от Ext.Loader, но не использовать метод loadScriptFile(), как было предложено выше.

В Ext 4 вводится система классов. Одним из (многих) преимуществ этого является де-дерево, которое позволяет вам управлять всеми вашими зависимостями между компонентами и загружать классы по мере необходимости.

Вот как вы инициализируете загрузчик

Ext.Loader.setPath('App','/js/app');
Ext.Loader.setPath('WidgetsLibrary','/js/widgets');
Ext.Loader.setConfig({enabled: true});

Определить динамически загруженный класс контроллера:

Ext.define('App.controller.Menu', {
    extend: 'Ext.app.Controller',      // leave it as it is
    models: ['Event','User'],          // this assumes App.model.* prefix
    stores: ['Options','Permissions'], // this assumes App.store.* prefix
    views:  ['menu.Bar','SmartButton'],// this assumes App.view.* prefix
    requires: [
        'App.whatever.other.class',    // auto-load this class as a dependency
        'WidgetsLibrary.*',            // auto-load all classes in WidgetsLibrary
    ],

    init: function(){}

 // [...]

Теперь динамически загрузите свой класс контроллера (макет):

Ext.require(                   
    'App.controller.Menu',     // this auto-loads all dependencies 
    function(){ 
        // ... as soon as this class 
        //    and all its dependencies have loaded...
        var controller = Ext.create('App.controller.Menu');  // create an instance
        controller.init();                                   // launch init() method
    }
);

БОНУС:, используя систему классов и загрузчик, вам не нужно поддерживать собственную коллекцию контроллеров и проверять, был ли контроллер загружен или нет. Просто используйте Ext.ClassManager.isCreated() метод, описанный здесь.

if(Ext.ClassManager.isCreated('App.controller.Menu')){
    // ... controller has already been loaded and init ... 
}else{
    // we need to auto-load that controller using Ext.require()
}

Дополнительная информация:

Ответ 3

Мы только что прошли через наш webapp. ~ 250 экранов. Да, мы динамически загружаем наши контроллеры.

Время создания экрана с использованием Ext.JS примерно на 400% быстрее, чем использование YUI, который был нашей предыдущей платформой. Хорошим было то, что мы могли бы сохранить объект YUI Connect, который работает с лучшей эффективностью, чем версия Ext.JS.

У нас есть класс App, который управляет загрузкой и инициализацией контроллеров Ext.JS. Здесь мы используем только один класс YUI в нашем коде, который является YUI.get(YUI.get.script). Просто убедитесь, что вы не загружаете контроллер дважды в тот же сеанс.

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

Ext.define('namespace.classname', {
{
    extend: 'Ext.form.panel',
    // your code here
}

Это снизит общую загрузку кода и ускорит инициализацию.

Ответ 4

Пока я не знаю, будет ли это работать (никогда не пробовали), я бы посмотрел на метод Ext.app.Application.getController(). Из ссылка api:

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

Таким образом, теоретически вы можете вызвать getController() с вашим динамически определенным контроллером и создать его.

Одностороннее примечание, которое я узнал при просмотре Ext 4. Контроллеры не могут запускать события, поэтому для обмена данными между контроллерами необходимо активировать события объекта Application, описанные в этот пост

Ответ 5

Я задал такой же вопрос здесь: http://www.sencha.com/forum/showthread.php?151220-Adding-controllers-views-dynamically-in-Ext-MVC-pattern

Не похоже, что это хорошо поддерживается в текущем Ext 4. С тех пор я переключил направление и не использую MVC-архитектуру, которую предоставляет Ext, и вместо этого использую те же методы, что и в Ext 3, добавляя/загрузка дополнительных компонентов на определенные обработчики (кнопки или ссылки, зависания, поиск и т.д.).

В моем приложении все мои компоненты являются настраиваемыми расширениями базовых классов Ext и действительно в конечном итоге действуют как контроллер, а суперклассы - это представление. Например, если у меня есть расширение Ext.panel.Panel, помимо начальной конфигурации items и layout, я не делаю ничего, что влияет на представление (все это обрабатывается в базовом классе). Большая часть класса привязывает обработчики и другие элементы к панели, чтобы обеспечить поведение приложения, которое в основном является определением контроллера. Это не идеально, но, по-моему, это лучше, чем нынешняя альтернатива.

Если вам нужны какие-либо примеры того, о чем я говорю, или вопросы о моей конкретной реализации, дайте мне знать, и я буду рад помочь.