Разработайте компонент формы, который принимает данные от пользователя и отображает форму.

Опубликовано: 1 Декабря, 2021

Дизайн: вот что он должен поддерживать:

  • Группировка полей формы
  • Проверки полей
  • Кнопка "Отправить"

Например, пользователь может захотеть проверить, является ли ввод допустимым адресом, и может захотеть, чтобы этот компонент имел проверки по умолчанию для электронной почты и т. Д.
Давайте попробуем создать очень простую модель данных для нашего компонента.

Для нашей минималистичной реализации мы могли бы захотеть использовать эти поля.

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

Выход: