Понедельник утро... самое время собрать мозги в кучу!
На этот раз расскажу об одной интересной наработке - как я программно создаю форму
Dojo из JSON. Задумав сие я стал бродить по интернету и наткнулся на весьма интересный
пост. Он то и послужил основой для моего класса.
Прежде всего, для затравки, покажу как выводится форма:
dojo.xhrGet({
url: '/path/to/form/json/',
handleAs: 'json',
load: function(data) {
var form = new JSONForm(data);
dojo.byId('container').innerHTML = form.generate();
}
});
Сгенерированный HTML код формы будет размещен в контейнере c ID
container. Просто и быстро.
JSON код (основной) формы в моем случае выглядит так:
{
"id" : "form_id", /* ID формы */
"params" : /* Параметры формы */
{
"action" : "/path/to/form/post/",
"encType" : "multipart/form-data",
"method" : ""
},
"fields" : /* Массив полей */
[
{
"name" : "field_name", /* Название поля в формы */
"widget" : "TextInput", /* Тип виджета */
"params" : /* Параметры, передаются конструктору виджета Dojo */
{
"id" : "field1_id", /* ID виджета Dojo (domeNode) */
"label" : "Подпись:", /* Подпись поля */
"name" : "widget_name" /* Название HTML элемента формы */
/* любые другие параметры для виджета */
}
}
]
}
Тут стоит рассказать о нескольких моментах:
- в отличии поста на stackoverflow.org, я передаю не класс Dojo виджета в параметре widget, а, вообще говоря, ключ по которому мой класс JSONForm делает отображение на класс Dojo виджета
- у поля есть два свойства name: одно непосредственно в объекте field, а другое в объекте params. Дело в том, что форма на сервере (а я использую Django forms) помимо названия полей имеет еще и префикс для того, чтобы можно было скомбинировать несколько форм с одинаковыми именами полей под одним тегом формы. Так что field.name - это имя поля в форме, а field.params.name - имя поля в HTML коде.
Теперь, когда понятно в каком виде приходит форма с сервера и как она выводится, перейдем к классу
JSONForm. Безусловно он написан с помощью
классов Dojo.
dojo.declare('JSONForm', null, {
/*
* Отображение типов виджетов, пришедших с сервера на Dojo воджеты
*/
_widget2dijit: {
'Textarea': dijit.form.Textarea,
'PasswordInput': dijit.form.ValidationTextBox,
...
},
/*
* Конструктор
*/
constructor: function(/* JSON Form Object */json) {
// параметры формы
this.id = json.id;
this.params = json.params;
this.params['id'] = this.id; // надо для создания виджета
// создадим форму
this.form = new dijit.form.Form(this.params);
// поля формы
this.fields = [];
// поля формы с ключем по имени поля
this.fields_dict = {};
// создадим поля
dojo.forEach(json.fields, function(item, index){
this.fields[index] = this._get_dijit(item);
this.fields_dict[item.name] = this.fields[index];
}, this);
},
/*
* Получим класс Dijit'a
*/
_get_dijit: function(field) {
var widget = this._widgit2dijit[field.widget];
return widget(field.params);
},
/*
* Генерация формы
*/
generate: function() {
// получим тег формы
var form = this.form.domNode;
// добавим поля
dojo.forEach(this.fields, function(item, index){
dojo.place(item.domNode, form);
}, this);
// добавим кнопку submit
var submit = new dijit.form.Button({
type: "submit",
label: "Отправить"
});
dojo.place(submit.domNode, form);
// вернем HTML нашей формы
return form.domNode.innerHTML;
}
});
Этого достаточно для создания и простейшего отображения полей.
Что с этим делать дальше? Это только часть кода (и весьма упрощенная), которую я использую у себя в классе, однако, дальше развитие может пойти так:
- Шаблоны с _Templated для большего контроля отображения формы.
- AJAX валидация полей - следующее чем хочу поделиться.
- AJAX отправка формы.
Если на стороне клиента есть необходимость отлавливать события полей, то это легко можно сделать с помощью
dojo.connect (или
dijit.connect):
dojo.xhrGet({
url: '/path/to/form/json/',
handleAs: 'json',
load: function(data) {
// создадим форму
var form = new JSONForm(data);
// присоединимся к событию onFocus поля "field1"
form.fields_dict["field1"].connect(form.fields_dict["field1"],
"onFocus", function(){ alert('Фокус!'); });
// отобразим форму
dojo.byId('container').innerHTML = form.generate();
}
});
Ну как? надеюсь был полезен.