Разработайте компонент формы, который принимает данные от пользователя и отображает форму.
Дизайн: вот что он должен поддерживать:
- Группировка полей формы
- Проверки полей
- Кнопка "Отправить"
Например, пользователь может захотеть проверить, является ли ввод допустимым адресом, и может захотеть, чтобы этот компонент имел проверки по умолчанию для электронной почты и т. Д.
Давайте попробуем создать очень простую модель данных для нашего компонента.
Для нашей минималистичной реализации мы могли бы захотеть использовать эти поля.
- Id: идентификатор поля
- Тип: текст / раскрывающийся список и т. Д.
- Подтип: для текста типа ввода нам может понадобиться пароль и т. Д.
- Значения: для раскрывающегося списка / Радио
- Валидатор: настраиваемый валидатор, предоставляемый пользователем. Мы можем использовать значение «email» и т. Д., Чтобы обеспечить проверку по умолчанию.
- Группа: группа, к которой должно принадлежать это поле.
- Заполнитель: заполнитель, если необходимо для поля.
- Обработчик: чтобы предоставить обратный вызов / вариант для нажатия кнопки отправки
Для этого мы попытаемся использовать шаблон MVC в JS. Во-первых, давайте разработаем наш модельный класс.
Для нашей минималистичной реализации мы сохраним входные данные для этого компонента в нашем классе модели.
Наша модель будет иметь входные данные для компонента, который теперь будет жестко закодирован, и событие, которое уведомит об изменении наших входных данных.
Вот минималистичная реализация
function ListModel() { this ._formInput=[ { "id" : "id1" , "type" : "text" , "name" : "name" , "placeholder" : "name" , "values" : "" , "validator" : function () { console.log( "test1" ); } , "group" : "gr1" } , { "id" : "id2" , "type" : "dropdown" , "name" : "name" , "placeholder" : "name" , "values" :[1, 2, 3], "validator" : function () { console.log( "test2" ); } , "group" : "gr2" } , { "id" : "id3" , "type" : "radio" , "name" : "name" , "placeholder" : "name" , "values" :[ "male" , "female" ], "validator" : function () { console.log( "test" ); } , "group" : "gr3" } , { "id" : "id4" , "type" : "button" , "name" : "name" , "placeholder" : "name" , "values" : "" , "handler" : function () { console.log( "test3" ); } , "group" : "gr3" } ]; this .itemAdded= new Event( this ); } ListModel.prototype= { addItem: function () { this .itemAdded.notify(); } , getFormInput: function () { return [].concat( this ._formInput); } , } ; |
Здесь класс событий - это базовая реализация pub / sub, где каждый модуль может реагировать на событие. Вот класс события
function Event(sender) { this ._sender = sender; this ._listeners = []; } Event.prototype = { attach: function (listener) { this ._listeners.push(listener); }, notify: function (args) { var index; for (index = 0; index < this ._listeners.length; index += 1) { this ._listeners[index]( this ._sender, args); } } }; |
Теперь перейдем к нашему контроллеру. В нашем примере использования мы добавили триггерные элементы в модель только при инициализации контроллера.
Ниже представлен класс:
function ListController(model, view) { this ._model = model; this ._view = view; var _this = this ; _this.returnResult(); } ListController.prototype = { returnResult : function () { this ._model.addItem(); } }; |
Теперь перейдем к нашему основному классу, который в конечном итоге будет отображать форму, которая является нашим классом представления.
Вот класс представления:
function ListView(model) { this ._model = model; var _this = this ; this ._model.itemAdded.attach( function () { _this.addResult(); }); this ._validators = []; } |
Здесь мы храним модель (которая в нашем случае является входом для этого компонента) и валидаторы для каждого поля.
Кроме того, мы присоединяем обработчик событий к нашему изменению модели, которое создаст представление. Вот полный код
ListView.prototype = { addResult: function () { var data = this ._model.getFormInput(); this .createContent(data); }, createContent: function (data) { var totalFieldGroup = []; var fieldGroup = []; var groups = {}; for ( var itr = 0; itr < data.length; itr++) { if (!totalFieldGroup.includes(data[itr][ "group" ])) totalFieldGroup.push(data[itr][ "group" ]); if ( typeof data[itr][ "validator" ] == "function" ) this ._validators.push(data[itr][ "validator" ]); } var form = document.createElement( "form" ); for ( var j = 0; j < totalFieldGroup.length; j++) { fieldGroup.push(data.filter( function (individual) { if (individual[ "group" ] == totalFieldGroup[j]) { return true ; } else { return false ; } })); var fieldset = document.createElement( "fieldset" ); var legend = document.createElement( "legend" ); legend.innerHTML = fieldGroup[0][0][ "group" ]; fieldset.appendChild(legend); this .createComponent(fieldGroup, fieldset); form.appendChild(fieldset); fieldGroup = []; } var subbtn = data.filter( function (individual) { if (individual[ "type" ] == "button" ) { return true ; } else { return false ; } }); if (subbtn.length == 0) { alert( "no submit button found" ); return ; } var btn = this .addSubmitButton(subbtn, form); form.appendChild(btn); form.setAttribute( "id" , "parentForm" ); document.body.appendChild(form); }, addSubmitButton: function (subbtn, form) { var x = document.createElement( "button" ); x.setAttribute( "type" , "submit" ); x.innerHTML = "Submit" ; var self = this ; x.addEventListener( "click" , function () { for ( var i = 0; i < self._validators.length; i++) { self._validators[i](); } subbtn[0][ "handler" ](); form.submit(); }); return x; }, createComponent: function (fieldGroup, fieldset) { var ret = fieldset; for ( var i = 0; i < fieldGroup.length; i++) { switch (fieldGroup[0][i].type) { case "text" : var label = document.createElement( "label" ); label.innerHTML = fieldGroup[0][i].name; var x = document.createElement( "INPUT" ); x.setAttribute( "type" , "text" ); x.setAttribute( "placeholder" , fieldGroup[0][i].placeholder); x.setAttribute( "id" , fieldGroup[0][i].id); fieldset.append(label); fieldset.append(x); break ; case "dropdown" : var label = document.createElement( "label" ); label.innerHTML = fieldGroup[0][i].name; var select = document.createElement( "select" ); select.setAttribute( "id" , fieldGroup[0][i].id); for ( var k = 0; k < fieldGroup[0][i].values.length; k++) { var option = document.createElement( "option" ); option.innerHTML = fieldGroup[0][i].values[k]; select.appendChild(option); } select.setAttribute( "placeholder" , fieldGroup[0][i].placeholder); fieldset.append(label); fieldset.append(select); break ; case "radio" : var label1 = document.createElement( "label" ); label1.innerHTML = fieldGroup[0][i].name; var label = document.createElement( "radiogroup" ); for ( var k = 0; k < fieldGroup[0][i].values.length; k++) { var radio = document.createElement( "input" ); radio.type = "radio" ; radio.label = fieldGroup[0][i].values[k]; radio.innerHTML = fieldGroup[0][i].values[k]; radio.value = fieldGroup[0][i].values[k]; label.appendChild(radio); } label1.appendChild(label); fieldset.append(label1); break ; } } } }; |
Вот как мы создаем экземпляр компонента
window.onload = function () { var model = new ListModel([]), view = new ListView(model), controller = new ListController(model, view); }; |
Выход: