[

понедельник, 11 июля 2011 г.

Программное создание Dojo формы из JSON

Понедельник утро... самое время собрать мозги в кучу!

На этот раз расскажу об одной интересной наработке - как я программно создаю форму 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 элемента формы */
            /* любые другие параметры для виджета */
          }
      }
    ]
}

Тут стоит рассказать о нескольких моментах:

  1. в отличии поста на stackoverflow.org, я передаю не класс Dojo виджета в параметре widget, а, вообще говоря, ключ по которому мой класс JSONForm делает отображение на класс Dojo виджета
  2. у поля есть два свойства 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;
    }
});

Этого достаточно для создания и простейшего отображения полей.

Что с этим делать дальше? Это только часть кода (и весьма упрощенная), которую я использую у себя в классе, однако, дальше развитие может пойти так:

  1. Шаблоны с _Templated  для большего контроля отображения формы.
  2. AJAX валидация полей - следующее чем хочу поделиться.
  3. 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();
    }
});

Ну как? надеюсь был полезен.

1 комментарий:

  1. Этот комментарий был удален администратором блога.

    ОтветитьУдалить