Динамически управлять 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
, я не делаю ничего, что влияет на представление (все это обрабатывается в базовом классе). Большая часть класса привязывает обработчики и другие элементы к панели, чтобы обеспечить поведение приложения, которое в основном является определением контроллера. Это не идеально, но, по-моему, это лучше, чем нынешняя альтернатива.
Если вам нужны какие-либо примеры того, о чем я говорю, или вопросы о моей конкретной реализации, дайте мне знать, и я буду рад помочь.