Принцип загрузки админки на ExtJs. Для новичков

В этой статье хочу немного развеять тучи над механизмом работы админки, логика которой основана на ExtJs. Для людей, далеких от php и javascript, это будет набором непонятных слов. А вот те, кого уже не пугают такие термины как ООП, наследование, конструкторы, поймут о чем я тут буду говорить. Это не курс. Я просто попытаюсь систематизировать информацию для понимания общего принципа работы админки.
В сети достаточно много различной информации об ExtJs. Есть отличный курс Василия, по которому многие из нас учились делать свои дополнения. В нем он разбирает тему создания различных ExtJs объектов. Я не буду повторять, то что у него уже разобрано, а постараюсь на простом языке сделать короткую выжимку. Начнем.

Загрузка админки на примере вызова компонента modExtra

Работа админки построена на контроллерах. Нажимаете на пункт меню какого-нибудь приложения, вызывается соответствующий контроллер, которых по цепочке запускает ряд действий (у Василия подробно это расписано). В конечном итоге вызывается контроллер «home.class.php», в котором и происходит подключение компонента на страницу. В глобальном масштабе это выглядит так — формируется структура HTML страницы админки (секции head, body):
— в head'e подключаются скрипты и стили, определяются важные системные параметры;
— в body формируется интерфейс — слева дерево. Шаблон
<div id="modx-leftbar"></div>
справа — выбранный контент компонента. Шаблон
<div id="modx-content"></div>
А вот за формирование правой части интерфейса как раз и отвечает контроллер home.class.php. Он определяет шаблон (div элемент), загружает скрипты компонента и подключает компонент на страницу.

Теперь давайте разберемся как ExtJs подключает компонент


Вот скрипты подключения из контроллера home.class.php.
public function loadCustomCssJs() {
	$this->addCss($this->modExtra->config['cssUrl'] . 'mgr/main.css');
	$this->addCss($this->modExtra->config['cssUrl'] . 'mgr/bootstrap.buttons.css');
	$this->addJavascript($this->modExtra->config['jsUrl'] . 'mgr/misc/utils.js');
	$this->addJavascript($this->modExtra->config['jsUrl'] . 'mgr/widgets/items.grid.js');
	$this->addJavascript($this->modExtra->config['jsUrl'] . 'mgr/widgets/items.windows.js');
	$this->addJavascript($this->modExtra->config['jsUrl'] . 'mgr/widgets/home.panel.js');
	$this->addJavascript($this->modExtra->config['jsUrl'] . 'mgr/sections/home.js');
	$this->addHtml('<script type="text/javascript">
	Ext.onReady(function() {
		MODx.load({ xtype: "modextra-page-home"});
	});
	</script>');
}
Само подключение на страницу происходит в последней строчке методом MODx.load(), который загружает компонент ExtJs, зарегистрированный как «modextra-page-home», когда страница отрендерена и DOM построен. Проще говоря, происходит что-то типа new Class(), где Class — это «modextra-page-home». А сам класс предварительно был определен и загружен в предыдущей строчке
$this->addJavascript($this->modExtra->config['jsUrl']. 'mgr/sections/home.js');
modExtra.page.Home = function (config) {
	config = config || {};
	Ext.applyIf(config, {
		components: [{
			xtype: 'modextra-panel-home', 
			renderTo: 'modextra-panel-home-div'
		}]
	});
	modExtra.page.Home.superclass.constructor.call(this, config);
};
Ext.extend(modExtra.page.Home, MODx.Component);
Ext.reg('modextra-page-home', modExtra.page.Home);
Те, кто знает ООП, глядя на этот код понимает, что тут у глобального объекта modExtra (который определяется в файле modextra.js и загружается в контроллере index.class.php), у свойства page определяется функция-конструктор Home, которая добавляет на страницу объект ExtJs с xtype'ом (проще говоря классом) 'modextra-panel-home' с помощью метода _addComponents(), который был унаследован от MODx.Component. Этот метод добавляет все объекты, чьи xtype перечислены в свойстве components.

Давайте теперь глянем на файл modextra.js
var modExtra = function (config) {
	config = config || {};
	modExtra.superclass.constructor.call(this, config);
};
Ext.extend(modExtra, Ext.Component, {
	page: {}, window: {}, grid: {}, tree: {}, panel: {}, combo: {}, config: {}, view: {}, utils: {}
});
Ext.reg('modextra', modExtra);

modExtra = new modExtra();
Тут все достаточно понятно. Определяется конструктор объекта modExtra. У него определяются свойства page, window и т.д., которые в свою очередь тоже являются объектами javascript. Таким образом, у modxExtra могут быть определены, например, несколько окон — modExtra.window.CreateItem и modExtra.window.UpdateItem. А в конце скрипта создается сам объект через new modExtra(). Он должен вызываться раньше все остальных скриптов компонента.

Хочу заметить, что в ExtJs используется 2 способа создания объектов — прямой и ленивый. Прямой — это когда объект создается непосредственно через конструкцию Ext.create(). А ленивый — через xtype. Этот пример мы уже видели выше
components: [{
	xtype: 'modextra-panel-home', 
	renderTo: 'modextra-panel-home-div'
}]
Функция Ext.reg() нужна, чтобы зарегистрировать xtype для последующего ленивого создания.

Осталось разобраться с появлением таблиц и форм. Давайте вернемся к файлу home.js, в котором указывается объект ExtJs с xtype 'modextra-panel-home'. Это панель c закладками нашего компонента modExtra. Именно ее мы видим открывая приложение. Она определяется в файле home.panel.js. А в самой панели через свойства xtype подключаются нужные объекты — таблицы, формы и т.п.

Вот такая схема. Надеюсь, получилось понятно и для полезно для новичков.
Сергей Шлоков
01 ноября 2015, 14:22
modx.pro
27
3 314
+16
Поблагодарить автора Отправить деньги

Комментарии: 20

Fi1osof
01 ноября 2015, 13:29
+1
В MODX, для рендеринга своих компонентов в страницу, лучше использовать не renderTo, а MODx.add(Object||xtype). В старых версиях MODX можно было передавать только xtype, на сколько я помню, но уже давно (по-моему с версии 2.3.0) передавать можно и объект.
Этот метод предпочтительней, так как рендерит элемент в специально отведенный див, в котором корректно будет учитываться высота экрана и т.п. Иначе рескуете намучиться со скроллом (точнее его отсутствием).
    Это сообщение было удалено
      Это сообщение было удалено
        Это сообщение было удалено
          Это сообщение было удалено
            Это сообщение было удалено
    Василий Наумкин
    01 ноября 2015, 16:30
    +2
    Почистил комментарии.

    Думаю, стоит опубликовать заметку обратно, учитывая оценку +7 и 5 добавлений в избранное.
      Fi1osof
      01 ноября 2015, 17:40
      +1
      ОК, с грубыми комментариями понятно. Но коммент, в котором аргументируются мои утверждения на счет renderTo и MODx.add() зачем удалять? Там все подробно расписано что и почему.
      Вынес его в топик, пригодится.

      P.S. вообще всегда убивала эта манера с технологий на эмоции переходить. Оценивать надо технологии правильно в них что-то или не правильно, а не то, кто что и как сказал.
        Василий Наумкин
        01 ноября 2015, 19:12
        0
        Но коммент, в котором аргументируются мои утверждения
        Там тоже эмоций завались.

        Ничоси… Вот так вот теперь новички реагируют на советы знающих людей?
        и далее по тексту…
          Fi1osof
          01 ноября 2015, 19:19
          -1
          ОК, вырезал бы эмоции, возникшие в ответ на эмоции. Но сама суть очень сильно относится к топику, ибо в топике половина не правильно. Какой смысл удалить правильное и аргументированное, оставив неправильное? В чем профит?
            Василий Наумкин
            01 ноября 2015, 19:21
            +2
            Суть в модерации срачей.

            Напиши свой топик, правильный, если считаешь нужным.
              Это сообщение было удалено
                Это сообщение было удалено
                  Это сообщение было удалено
            Володя
            01 ноября 2015, 22:40
            0
            спасибо за renderTo и add, теперь ясно отчего такой скрол непредсказуемый.
            Вопрос — чтоб не иметь проблем то как лучше добавить панель на страницу?
            создать сначала пустую панельку через renderTo и затем через add добавить функциональную панель?
            примерно так?
            var p = Ext.ComponentMgr.create({
            	xtype: 'panel',
            	renderTo: "id" 
            });
            var panel = new base.panel.Home();
            p.add(panel);
            p.doLayout();
              Fi1osof
              01 ноября 2015, 22:48
              0
              Не за что.

              Вообще не надо добавлять create и т.п. на уровне инициализации. Из-за этого не получится инициализировать объект отдельно, без непосредственного рендеринга в страницу, для собственных нужд. К примеру, вы захотели вывести его во всплывающем окне? А там renderTo… В базовом случае (в том числе и в случае с modExtra) вообще шаблон не нужен. И если надо вывести свой элемент в страницу, правильней писать так:
              $this->modx->regClientStartupScript('<script type="text/javascript">Ext.onReady(
              	function(){MODx.add("my-xtype")});</script>', true);
              Или так:
              $this->modx->regClientStartupScript('<script type="text/javascript">
              	Ext.onReady(function(){MODx.add(new MyClass(params))});</script>', true);
              Раньше, когда в MODx.add() можно было передавать только xtype и нельзя было передавать параметры, еще имел смысл как можно больше параметров прописать в сам класс. Но теперь можно на лету создать объект с передачей в него нужных параметров и добавить его через MODx.add(). А там уже пусть сам MODx разбирается куда это дело вывести в зависимости от версии MODX-а.
                Володя
                01 ноября 2015, 22:52
                0
                это мне понятно. Смысл в том чтоб вывести нужную панель в конкретно указанном id
                посмотри тут ecc.vgrish.ru/
                и иного решения как выше я пока не придумал.
                  Fi1osof
                  01 ноября 2015, 23:03
                  +1
                  А так не?
                  var p = Ext.ComponentMgr.create({
                  	xtype: 'panel',
                  	renderTo: "id" 
                  	,items: [
                  		new base.panel.Home()
                  		// и тут еще перечисление итемов через запятую xtype-ами или готовыми объектами
                  	]
                  });
                    Володя
                    01 ноября 2015, 23:04
                    0
                    не ну эт тож так же) Ок. Спасибо, вопрос решен!
                      Сергей Шлоков
                      02 ноября 2015, 07:56
                      0
                      А можно более привычно
                      var p = Ext.create({
                      	xtype: 'panel',
                      	renderTo: "id" 
                      	,items: [{
                      		// xtype объекта base.panel.Home
                      		xtype: 'base-panel-home'
                      		,id: 'id объекта'
                      		// перечень других свойств
                      	}]
                      });
          Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
          20