Начало начал или пошаговое создание простой формы на ExtJS
Приветствую всех наших читателей, и сразу прошу прощения за долгое отсутствие, честно, был сильно занят как в офф-лайне, так и здесь, так что это был вынужденный перерыв, и, поверьте, сам уже заскучал за блогом. А пообщавшись в привате с несколькими людьми, я заметил, что начинающие изучать AJAX на примере ExtJS часто не могут разобраться даже с самой основой - созданием и обработкой обычной формы. Поэтому я решил написать руководство, попутно разобрав внутренности библиотеки. Замечу, что основываться мы будем на версии ExtJS 1.1.1, а про 2.0 поговорим в одном из следующих выпусков.
И так, формы в ExtJS основываются на основном классе BasicForm. Этот класс, с которым напрямую вы не будете контактировать, описывает основное поведение форм, в том числе и реакцию на подтверждение (отправку данных). Это событие в терминах ExtJS имеет название "do actions". Основная же форма будет конструироваться на основе класса Ext.form.Form.
У этого класса есть очень много свойств и методов, так что мы не станем рассматривать их все, а сначала остановимся только на событиях, остальное же будем изучать по мере создания нашего примера.
- actioncomplete - событие возникает, когда форма успешно обработана.
- actionfailed - событие, когда форма не обработана или в процессе возникли ошибки.
- beforeaction - событие предшествует обработке формы, так что если вам надо встроить свою проверку или другие действия, которые могут повлиять на всю форму - вставьте свой код здесь, а для отмены последующей обработки формы верните false.
- clientvalidation - формы в ExtJS имеют возможность валидации данных непосредственно на клиенте, а это событие происходит при проверке формы и передаёт флаг результата проверки true если все отлично, и false, если форма заполнена неверно.
В нашем примере мы будем создавать форму для регистрации на каком-либо сайте, для примера я взял регистрационную форму от одного из своих проектов. Конечный вариант выглядит следующим образом:

Кстати, заметили красные подчёркивание и значки возле формы? Это как раз валидация формы, а когда она не заполнена, естественно, что все поля не проходят проверку. А значки рядом - это подсказки про поле, там, например, можно написать, как верно заполнять форму, а позже, при проверке, выводить предупреждение о неверности заполнения. При пустой форме там указывается на те поля, которые объявлены как обязательные для заполнения.
Теперь начнём подготовку к созданию формы. Создаём обычную HTML страницу, в которой подключаем необходимые файлы ExtJS, думаю, этот момент не вызовет сложностей, поэтому опускаю его. Сама форма требует одного или нескольких элементов div на странице, которые обеспечат ей место для отображения и сопутствующие элементы. Я использовал часть кода с одного из примеров:

Блоки из трёх вложенных div-тегов с классами x-box-* отвечают за формирование этой самой рамки с заокругленными углами и тенями, в принципе, это вам может и не понадобится. Основной элемент - это внутренний div с идентификатором "register_form", именно он будет указываться как основа для рендеринга формы.
Теперь дело за наполнением. Дело в том, что есть как минимум два варианта создания и наполнения формы отдельными элементами управления. Первый состоит в том, что мы прямо в конструкторе описываем все элементы в виде JSON массива или объявления объектов, именно так сделано в тестовых примерах в документации. Честно говоря, я почему-то считаю, что этот метод не всегда самый лучший, так как сложно потом обращаться напрямую к определённым элементам формы (но можно через метод findField). Либо вручную создавать отдельные объекты полей формы, настраивать их поведение как нужно, а потом добавлять в существующую форму через метод add.
В нашем примере мы пойдём по пути официальной документации и сразу опишем все поля формы.
Но сначала нужно объявить саму форму и настроить QuickTips, который используется для валидации данных. Делается это следующей строкой в самом начале скрипта:
Ext.QuickTips.init(); Ext.form.Field.prototype.msgTarget = 'side';
Далее, для удобства, объявляем переменную, которая будет хранить весь объект формы:
var reg_form;
Теперь мы подошли к самому главному - описанию самой формы. Сначала определяется форма и ее основные данные:
- url - адрес, куда будут отправлены данные формы. Для примера: http://ваш.серевер/form_script.php
- timeout - таймаут ожидания ответа от сервера, в секундах, по умолчанию 30 секунд.
- method - метод, которым отправляются данные на сервер, GET или POST.
- labelWidth - длина описаний для полей, в пикселях.
- labelAlign - где по отношению к полю размещается описание.
- fileUpload - если в форме используется загрузка файлов, то этот флаг следует установить в true.
- buttonAlign - выравнивание кнопок формы, например кнопок submit/cancel.
- Если вы используете XML вместо JSON для обмена данными с сервером, необходимо переопределить свойства errorReader (отвечает за получение данных об ошибках заполнения формы от сервера) и reader.
- baseParams - если вам необходимо передавать какие-то особые параметры вместе с формой, например, идентификатор сессии, то вместо hidden-полей лучше всего использовать это свойство, присваивая ему объект с необходимыми параметрами (или JSON-данные). Для передачи с формой идентификатора сессии можно сделать так: baseParams = {"PHPSESSID":"<?php echo session_id(); ?>"};
Вот и все основные параметры формы (остальные могут вам понадобиться при углублённом использовании различных продвинутых возможностей). А вот так выглядит код описания нашей формы с примера:
reg_form = new Ext.form.Form({
labelAlign: 'right',
labelWidth: 75,
url:'register_processed.php?PHPSESSID=<?php echo session_id(); ?>',
method: 'POST',
fileUpload : false,
timeout: 10
});
Как видите, вместо baseParams можно и напрямую присваивать необходимые переменные в строке url, они все равно будут переданы на сервер. Хотя это и вносит некоторую неразбериху, поэтому в реальных проектах все же выберите себе свой стиль.
Теперь немного о самой архитектуре формы. Она состоит из колонок, в которых содержаться наборы полей, объединённых в элемент fieldset ( да-да, аналог из HTML-а). То есть, сама форма состоит из иерархического набора вложенных элементов. Для нашей формы мы создаём одну колонку и в ней один набор полей. За это отвечает объект Ext.form.Column. У него есть достаточно много свойств, можете разобраться с ним, если будете создавать очень сложные формы, с множеством групп элементов и зависимостями между ними. Для нас сейчас это не так важно, поэтому просто создаём одну колонку размером 400 на 400 пикселей, а для заголовка отводим 100 пикселей:
reg_form.column({width:400, height: 400, labelWidth:100});
Далее нам необходимо создать набор полей формы. Основной для этого является объект Ext.form.FieldSet. Как и в его собрата из HTML, набор полей ограничивается рамкой, и можно задать название формы. Впрочем, при создании есть возможность определить достаточно много свойств, можете просмотреть документацию, нам же пригодится только свойство legend, в котором объявим название формы, а вторым параметром передадим массив наших элементов формы.
Для создания форм в ExtJS программисту доступно несколько различных объектов, реализующих основные элементы управления, известные нам по типичным интерфейсам ОС. Это:
- Ext.form.Checkbox
- Ext.form.ComboBox - достаточно продвинутый элемент, имеющий и автодополнение, и возможность заполнения данными с сервера и множество других "вкусностей".
- Ext.form.HtmlEditor - простой визуальный редактор. В 1.1 версии возможно только один редактор на странице.
- Ext.form.NumberField - расширенное обычное поле ввода для работы с цифровыми данными.
- Ext.form.Radio
- Ext.form.TextArea
- Ext.form.TextField
Это основные элементы, с которых мы будем строить нашу форму. Дополнительно нам пригодится еще класс Ext.form.VTypes, который предоставляет возможности валидации типичных данных для полей ввода. Пока по умолчанию доступны следующие типы: alphanum (только строчные и заглавные буквы и цифры, правда не работает с кириллицей), email (для проверки адресов электронной почты) и url для проверки адресов страниц. При необходимости можно реализовать и свою проверку.
В нашей форме мы будем использовать базовую проверку, встроенную в сами элементы - на минимальную и максимальную длину, а для некоторых полей, в которых заведомо должны быть только латинские символы, мы используем валидатор типа "alphanum".

Наш пример использует только обычные поля ввода, Ext.form.TextField, но работа с остальными не так и отличается, только в случае, к примеру, использования ComboBox с загрузкой данных с сервера. Мы пока будем изучать самую простую форму. В ней мы предусмотрим следующие поля и ограничения для них:
- Логин - от 4 до 20 символов, латинские буквы и цифры, обязательно должно быть заполнено.
- Пароль - те же требования, но нельзя отображать символы, их нужно заменить на знаки подстановки.
- Бета-ключ - обязательное поле, содержащие специальный код для регистрации, строго длина 32 символа.
- Имя - может содержать от 4 до 100 символов, и может содержать кириллицу, поэтому стандартный валидатор не пройдёт, проверять будем только заполнение и длину, а детальную проверку оставим на серверную сторону.
- Почтовый адрес - должен содержать только адрес e-mail и не может быть больше 100 символов. Здесь уместно использовать стандартный валидатор.
На рисунке сбоку показан этот участок кода, описывающий эти элементы. Заметьте, что можно устанавливать начальные значение полей через свойство value, а свойство allowBlank указывает на то, может ли поле оставаться пустым, или это будет считаться ошибочным заполнением и такое поле не пройдёт валидацию. Свойство vtype устанавливает необходимый валидатор для поля.
Теперь нам необходимо закрыть колонку, для этого используем код:
reg_form.end();
Для того, чтобы установить единую ширину всех элементов формы, можно применить метод applyIfToField() формы, который позволяет применить указанный объект с настройками для всех полей формы.
reg_form.applyIfToFields({
width:230
});
Далее можно уже заняться кнопками - ведь какая это форма без кнопок. Нам необходимо две кнопки - подтверждение ввода данных (submit), в качестве которой у нас выступает кнопка "Регистрация пользователя", и кнопка отмены, которая возвращает все поля формы в свои начальные значения.
Для добавления кнопок и связывания с ними обработчиков мы применим метод формы addButton. Вызывая его каждый раз мы будем добавлять кнопки, которые будут выстроены в порядке добавления слева направо.
Первой кнопкой будет кнопка регистрации, которая связана с специальным обработчиков формы - функцией form_data_eval, а вторая кнопка сразу вызывает метод reset нашей формы. Дополнительно мы задаём текстовую надпись для кнопок и их тип. Этот код выглядит следующим образом:
reg_form.addButton(
{handler: form_data_eval, text: 'Регистрация пользователя', type:'submit'},
form_data_eval, reg_form);
reg_form.addButton('Cancel', function(){ reg_form.reset(); });
Ещё я хочу перехватывать события формы, и соответственно реагировать на успешное завершение регистрации и ошибки. Для этого я прикрепляю свои обработчики к событиям формы actioncomplete и actionfailed, причем за первое отвечает моя функция, а второе описано просто в коде, выдавая сообщение об ошибке. Посмотрим, как это реализовано:
reg_form.on('actioncomplete', register_complate);
reg_form.on('actionfailed', function(){ Ext.MessageBox.alert('Ошибка!', 'Ошибка в процессе регистрации пользователя! Может, неверный BetaKEY?');});
Сама функция отправки данных очень проста. Сначала мы проверяем, верно ли заполнены все поля формы, для чего опрашиваем метод isValid формы, и в случае возврата true, отправляем форму методом submit. А в случае неверного заполнения вызываем метод, который отмечает все неверно заполненные поля.
function form_data_eval()
{
if (reg_form.isValid() == true)
{
reg_form.submit();
}
else
{
reg_form.markInvalid();
Ext.MessageBox.alert('Ошибка!', 'Ошибка, информация неверная!');
}
}
Обработка actioncomplete простая и заключается в выводе приветственного сообщения через функцию alert(). А вы можете подставить свою код.
Уфф, в этом выпуске все, в следующей части статьи мы рассмотрим, что же собственно, передаётся на сервер и как управлять этим, как оповестить клиент, что какое-то то поле не так заполнено и требует корректировки.




и нифига не пашет
что именно? знаете, чем отличается программист от остальных? либо вы конкретно напишите, что вы делаете, как и что именно не работает или работает по другому, нежели ожидается, тогда можно вам что-то подсказать. либо может стоит начать с чего-то более простого, чем сразу AJAX и ExtJS? как минимум с отладки и понимания работы AJAX веб-приложений.
Почему в API нет Ext.form.Form? Это пример со старой библиотекой, что ли? Сейчас я вижу Ext.form.FormPanel. Наверное другая реализация. Хотелось бы пример.
Ну, если внимательно читать, то да, написано в самом начале.. “Замечу, что основываться мы будем на версии ExtJS 1.1.1…”. На 2.0 я пытался сейчас делать новый проект, но так как с ней нужно больше разбираться, то решили сделать на уже изученной 1.1.1. Посмотрите Migration Guide на сайте, увидите что изменилось.
как то все же соберусь плотно изучить 2.0, тогда напишу
Взял их пример с формой. Взял пример Desctop. Пробую отобразить на рабочем столе, форма получается искаженной. Только в IE нормально. Куда копать?
Desktop как я помню, вроде в 2.0 пример появился.
а сами то примеры по отдельности работают? те которые идут в дистрибутиве?
Смотреть что значит искажет, смотреть фаербугом что не так., все ли подключается, все стили, пути и т.д.
Да, примеры работают. Если я в body рендерю, то форму вообще не видно. Видно слои рабочего стола перекрывают(я еще в firebug посмотрю), а если в div id=x-desctop, то форма искажается.
И еще вопрос, не могу понять что в библиотеке имеется ввиду под понятием layout?
значит трабла именно в совместимости, возможно в перекрытии слоев/стилей.
в боди рендерить не надо тогда точно ничего не будет.
Ну понимают компоненты, которые логически размечают всю страницу, организуя ее в несколько областей данных, которые имеют уже некоторый функционал (типа могут быть скрываемыми и т.д.), и в которые можно-нужно вставлять другие части страницы и можно рабоатть с ними как с обьектами, без доступа вручную до уровня тегов страницы.
Добавил в div рабочего стола ещё , и в него рендерю. Теперь нормально. Там ярлыки мешали со своими дивами. Теперь бы спозиционировать по центру.
Я, собственно, думал, что форма сама отрисуется как, например, алерты. Т.е, чтоб не привязывать к конкретному узлу. В общем, еще мало понимаю. уду копаться.
Нет ссылки на исходники. Хочется посмотреть подробнее.
каких где исходников? Ext-a есть
Например, как вытащить данные из response. В примере ничего не сказано. Пришлось копаться. И много других мелочей, которые для автора понятны, а начинающий непонимает о чем идет речь.
Кстати вопрос. Приходит success:false, допустим неправильный пароль. Почему форма маркирует первое поле name и вставляет подсказку. Как с этим бороться?
А, извиняюсь, во второй части вычитал
из респонса в форме вытащить напрямую нельзя, как я понял. это, правда есть немного сложность, но в обычных случаях это и не надо.
а примеров к статьям не будет, к этой в особенности, принципиально – я рассказываю о процессе исследования, подталкивая людей к изучению, а не копированию примеров. если есть конкретные вопросы, задавайте, обсудим и найдем решения.
reg_form.isValid – в 1.1 есть, а в 2.0 нет, Что делать ?
Пробовал reg_form.user_password
if (reg_form.user_password.isValid() == true)
{
user.submit();
}
НО тоже не получилось – reg_form.user_password has no properties.
В чём ошибка ?
есть в классе Ext.form.BasicForm либо использовать мониторинг с класса FormPanel
Вот тут разобрался
http://extjs.com/learn/Tutorial:Basic_Login
Надо было работать с reg_form.getForm().submit
ну это верно, правда более высокоуровнево – сабмит конечно сам проверяет правильность заполнения, только после этого сабмитит форму, а самому узнать верна она или нет, например, для добавления данных в басепарамс или для других действий все же придется использовать исвалид
Все же ориентироваться на старую библиотеку смысла нет
Спасибо за ответы на все вопросы
На самом деле узнал много нового. Вот только до конца так и не разобрался что и откуда.