Добрый день, хабрапользователи! Сегодня я бы хотел поделиться с проблемами, которые обычно отталкивают добропорядочных программистов от использования фреймворка — Ext JS. Опишу конкретную ситуацию: в один прекрасный день после некоторого времени потраченного на просмотр возможностей, которые предлагает Ext JS, возникает непреодолимое желание попробовать его «в деле». Качается дистрибутив, ставится на локальный сервер и запускаются красивые примеры гридов, форм и, даже, готового рабочего стола! Разработчик меняет пару «фишечек», все вроде легко и просто. Резонно в голове бой-скаута возникает идея сделать некий коммерческий проект на Ext JS (чаще всего это бывают различного рода CMS, админки, CRM). И тут начинается самое интересное…После недели работы с Ext JS голова бой-скаута начинает полуавтоматически генерировать мысли о его собственной ничтожности и невообразимой сложности Ext JS. И, обиженный на Ext JS, разработчик развевает по ветру пепел желания работы на этом фреймворке. А жаль…
Поэтому в этой статье я хочу описать проблемы, с которыми я столкнулся при разработке системы управления контентом и решения этих проблем. Все примеры проверены на Ext JS версии 3.4.
1. Автоматическая подгонка размеров содержимого окна.
Задача: встроить в Ext.Window форму (Ext.form.FormPanel). Первое, что приходит в голову:
Ext.onReady(function(){ var win = new Ext.Window({ title: "title", border: false, width: 400, height: 400, items: [{ width: 390, height: 380, items: [new Ext.form.FormPanel({ frame: true, items: {xtype: 'textfield'} })] }] }); win.show(); });
В данном случае разработчику требуется «подогнать» размеры формы под размеры окна. Если подогнано неверно — снизу появляется раздражающая белая полоска:

Для этой ситуации разработчики Ext JS предусмотрели параметр layout в конфигурации Ext.Window. Конкретно для этого случая используется layout: 'fit':
Ext.onReady(function(){ var win = new Ext.Window({ title: "title", border: false, width: 400, height: 400, layout:'fit', items: [ new Ext.form.FormPanel({ frame: true, items: {xtype: 'textfield'} }) ] }); win.show(); });

2. Разделение полей формы на 2 и более колонок (или размещение нескольких полей формы на одной строке).
Если просто прописать в items формы несколько полей формы, то они выстроятся ровно друг под дружкой, примерно вот так:
Ext.onReady(function(){ var win = new Ext.Window({ title: "title", border: false, width: 400, height: 200, layout:'fit', items: [ new Ext.form.FormPanel({ frame: true, items: [{ xtype: 'textfield', fieldLabel: 'field1' },{ xtype: 'textfield', fieldLabel: 'field2' },{ xtype: 'textfield', fieldLabel: 'field3' },{ xtype: 'textfield', fieldLabel: 'field4' }] }) ] }); win.show(); });

Нам же требуется, чтобы было примерно так:

Делается это так:
(Внимание! Для понимания следующего куска кода требуется немного логического мышления)
Ext.onReady(function(){ var win = new Ext.Window({ title: "title", border: false, width: 400, height: 200, layout:'fit', items: [ new Ext.form.FormPanel({ frame: true, // Нас интересует код от этого места layout: 'column', defaults: { xtype: 'form', columnWidth:0.5, labelAlign: 'top', anchor: '100%' }, // до этого // 1 items: [{ // 2, столбец 1 items:[{ xtype: 'textfield', fieldLabel: 'field1' },{ xtype: 'textfield', fieldLabel: 'field2' }] },{ // 3, столбец 2 items:[{ xtype: 'textfield', fieldLabel: 'field3' },{ xtype: 'textfield', fieldLabel: 'field4' }] }] }) ] }); win.show(); });
Итак. Приступим к разбору кода. Первое, что нужно для разделения формы на колонки параметр layout: 'column', который сообщает форме, что форму следует разделить на колонки. Далее вступает в дело параметр defaults, который сообщает настройки по умолчанию для нижестоящего items. Эти настройки передаются каждому объекту в этом массиве (объектам items 2, items 3).
Почему в defaults так много параметров и зачем они нужны, для простого разбиения формы на колонки? Отвечаю:
xtype: 'form' — без этого параметра, не отображались бы fieldLabel для каждого поля,
columnWidth — определяет ширину стобцов по умолчанию (в объектах 2 и 3 можно ширину столбца переопределять),
labelAlign — определяет положение fieldLabel (top — сверху),
anchor — ширина в процентах объектов 2 и 3.
Так же обратите внимани�� на то, что в отличие от предыдущего примера, в items объекта 1 добавляется еще один уровень вложенности.
3. Управление рендерингом записей в гриде.
Часто случается так, что хочется как-то изменить содержимое ячейки грида, в зависимости от будущего значения этого содержимого. На помощь приходит параметр грида — renderer.
Допустим у нас на старте есть грид:

Исходный код:
var data = { totalCount : 3, banners: [{"is_active": 0,"ID": 1},{"is_active": 0,"ID" : 3},{"is_active": 1,"ID": 4}] } var view = new Ext.Viewport({ layout: 'fit', items: [{ xtype: 'grid', columns: [ {header: "ID", align : 'left', width: 30, sortable: true, dataIndex: 'ID'}, { header: "Активность", align : 'left', width: 100, sortable: true, dataIndex: 'is_active' } ], store: new Ext.data.GroupingStore({ data: data, fields: [{name: 'ID'},{name: 'is_active'}], reader: new Ext.data.JsonReader({ root: 'banners', totalProperty: 'totalCount', id: 'ID' }, Ext.data.Record.create([ {name: 'ID'}, {name: 'is_active'} ]) ) }), view: new Ext.grid.GridView({ forceFit: false, }), listeners: {} }] }); view.render(Ext.getBody()); });
Можно сделать так:

Исходный код:
var renderActivity = function(val) { if(val == 1) return "<span style='color: green'>"+val+"</span>"; else return "<span style='color: red'>"+val+"</span>"; } var data = { totalCount : 3, banners: [{"is_active": 0,"ID": 1},{"is_active": 0,"ID": 3},{"is_active": 1,"ID": 4}] } var view = new Ext.Viewport({ layout: 'fit', items: [{ xtype: 'grid', columns: [ {header: "ID", align : 'left', width: 30, sortable: true, dataIndex: 'ID'}, { header: "Активность", align : 'left', width: 100, sortable: true, dataIndex: 'is_active', renderer: renderActivity } ], store: new Ext.data.GroupingStore({ data: data, fields: [{name: 'ID'},{name: 'is_active'}], reader: new Ext.data.JsonReader({ root: 'banners', totalProperty: 'totalCount', id: 'ID' }, Ext.data.Record.create([ {name: 'ID'}, {name: 'is_active'} ]) ) }), view: new Ext.grid.GridView({ forceFit: false, }), listeners: {} }] }); view.render(Ext.getBody()); });
Как видно, вначале была добавлена функция renderActivity, которая разукрашивает содержимое ячейки в зависимости от значения в зеленый или красный цвет. Далее эта функция вызывается в описании настроек колонки «Активность» — renderer: renderActivity. Таким образом содержимое ячеек грида можно легко и просто изменять под любые,
Если посвятить изучению Ext JS побольше врем��ни, то действительно поражаешься, какие гибкие возможности предоставляет этот фреймворк. Многие говорят, что сайты на Ext JS сложно кастомизировать. Не верьте этому. Лично я считаю, что у фреймворка просто достаточно высокий порог вхождения.
Разрабатывая на Ext JS уже около года, я «съел не одну собаку». Таких мелочей у меня накопилось великое множество. Поэтому, если хабрасообщество пожелает и в дальнейшем читать мои статьи по Ext JS, я с радостью их буду писать.
На этом извольте закончить мою первую статью, надеюсь она вам понравилась.
