Pull to refresh

Руководство по мелочам в Ext JS

Reading time5 min
Views39K
Добрый день, хабрапользователи! Сегодня я бы хотел поделиться с проблемами, которые обычно отталкивают добропорядочных программистов от использования фреймворка — 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();
});

В данном случае разработчику требуется «подогнать» размеры формы под размеры окна. Если подогнано неверно — снизу появляется раздражающая белая полоска:

image

Для этой ситуации разработчики 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();
});

image

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();
 
});

image

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

image

Делается это так:
(Внимание! Для понимания следующего куска кода требуется немного логического мышления)
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.

Допустим у нас на старте есть грид:

image

Исходный код:

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());
});


Можно сделать так:
image

Исходный код:

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, я с радостью их буду писать.

На этом извольте закончить мою первую статью, надеюсь она вам понравилась.
Tags:
Hubs:
Total votes 47: ↑45 and ↓2+43
Comments73

Articles