Добрый день, хабрапользователи! Сегодня я бы хотел поделиться с проблемами, которые обычно отталкивают добропорядочных программистов от использования фреймворка — 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, я с радостью их буду писать.
На этом извольте закончить мою первую статью, надеюсь она вам понравилась.
