Создание форм с помощью чистого HTML задача довольно тривиальная и подробно обсуждается в каждом уважающем себя учебнике. Но все становится куда сложнее, если вам нужно, например, разнести элементы формы по нескольким табам. В этом случае без фреймворка не обойтись. В этой статье я расскажу, как можно создать сложные веб-формы с помощью UI-фреймворка Webix.



Основы. Как создать простую форму


Сперва давайте разберемся с тем, как можно создать форму с помощью Form Component. В Вебикс все элементы интерфейса описываются через JSON. Для создания формы нужно использовать объект со свойство view:"form". У этого же объекта нужно задать свойство elements — это массив, содержащий элементы, из которых состоит ваша форма.

Вот как это работает:

webix.ui({
	view:"form",
	elements: [
		{ /* первый компонент формы */ },
		{ /* второй компонент формы */},
		{ /* и т.д. */}
	]
});


В качестве элемента формы можно использовать любой другой компонент Webix UI: текстовое поле, чекбокс, кнопку и т.п.

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

Итак, код:

webix.ui({
	view:"form",
	id:"myForm",
	container: "areaA",
	width: 350,
	elements: [
		{view:"text", label:"Username", name:"username"},
		{view:"text", label:"Password", name:"password",
		 type:"password"},
		{view:"checkbox", labelRight:"I accept terms of use",
		 name:"accept"},
		{view:"button", value: "Submit", width: 150, align:"center",
		 click:submit}
	]
});


Ничего такого, к чему бы мы не были готовы. Свойство view:"form" uговорит о том, что нас интересует именно форма. Свойства label работают также, как и HTML тег label. Получить значение каждого элемента формы можно через свойство name. Для того, чтобы скрыть вводимые символы в поле Password, используется свойство type:"password". Что интересно, так это свойство click:submit в коде описания кнопки. Оно определяет функцию, которая будет вызвана после того, как кнопка будет нажата. Это свойство необязательно, но будет полезно проверить с его помощью, всё ли хорошо с введенными данными.

Вот пример кода, который выводит на экран введенные значения. Для вывода сообщений в нем используется Webix Message Box:

function submit(){
	webix.message(JSON.stringify($$("myForm").getValues(), null, 2));
}


В этом примере с помощью метода getValues()мы получаем значения элементов Webix, а метод JSON.stringify() служит для преобразования полученных данных в строку JSON.

Итак, все готово и мы можем проверить результат:



После ввода данных можно проверить работу формы с помощью кнопки Submit:



Все работает как и положено. Поскольку нам теперь известны основы создания форм, можно попробовать создать что-то более сложное.

Код и демо можно глянуть здесь — webix.com/snippet/2259ec41

Использование сложных контролов на примере Multicombo


Webix предоставляет несколько контролов, помогающих пользователю с выбором во время работы с формами. На мой взгляд, один из самых интересных из них это Multicombo. Этот контрол позволяет реализовать множественный выбор из элементов выпадающего списка.

Например, вы хотите создать страницу для создания резюме разработчика. Вот упрощенный пример формы, которую вы можете использовать:



Поскольку вполне вероятно, что пользователь владеет более чем одним языком программирования и вы вооружены списком языков, это тот самый случай, когда можно использовать Multicombo. Вот пример файла data.js, который содержит нужные данные:

var languages = [
	{id:1, lang:"4th Dimension/4D"},
	{id:2, lang:"ABAP"},
	/* и т.д. */
]


Давайте используем Multicombo в поле Skills:

{view:"multicombo", name:"skills", label:"Skills", button: true, 
 suggest: {
      body:{
        data:languages,
        template:webix.template("#lang#")
      }
 },
}


Помимо уже знакомых нам свойств, в этом примере имеется и что-то новое. Свойство button: true создаст кнопку подтверждения выбора в выпадающем списке. Для того, чтобы указать источник содержимого для выпадающего списка используется свойство suggest. Можно, например, просто указать путь к файлу: suggest: "path/to/file/data.js". Но лучше всего использовать шаблон в комбинации со свойством data, что позволит извлечь из целевого архива именно те данные, которые вам нужны.

Ниже показан пример работы такого контрола. После клика в текстовом поле появится выпадающее меню с доступными для выбора вариантами:



Можно промотать список и выбрать нужные варианты или начать вводить текст:



Форма из этого примера вернет список ID выбранных пунктов:



Код и демо можно глянуть здесь — webix.com/snippet/63f6328e

Полезными также могут оказаться такие контролы как Grid Suggest и Dataview Suggest

Использование дерева как элемента формы


Webix не ограничивает вас использованием текстовых полей, кнопок, чекбоксов и прочих привычных компонентов в качестве элементов формы. В форму можно поместить практически любой виджет. Давайте попробуем сделать это на примере Tree. Он не был изначально предназначен для использования внутри формы, поэтому он не имеет методов setValue() и getValue(), необходимых для получения данных о выбранных элементах. Как это можно исправить? Можно использовать метод protoUI, который позволяет создавать новые элементы на основе уже имеющихся:

webix.protoUI({
	name:"formTree",
	setValue:function(value){ this.checkItem(value); },
	getValue:function(){ return this.getChecked(); }
}, webix.ui.tree);


В этом примере мы создали новый компонент, который называется formTree. Затем мы определили для него методы setValue() и getValue(). И, наконец, указали, что хотим создать новый компонент на основе дерева.

Прежде чем его использовать, давайте создадим необходимые данные для нашего дерева:

var treedata = [
	{ id: "1", value: "Web", data: [
		{ id: "1.1", value: "HTML" },
		{ id: "1.2", value: "CSS" },
		/* some more data */
	]},
	{id:"2", value:"Scripting", data: [
		{ id: "2.1", value: "Shell" },
		/* some more data here */
	]},
]


Теперь можно добавить новый элемент в форму. Сделать это можно так же, как и в случае с любым другим элементом:

{view:"formTree", name:"skills", data:treedata, 
 height: 150, threeState: true,
 template: "{common.icon()} {common.checkbox()}   #value#"
},


Свойство threeState:true включает 3-state checkboxes, а шаблон добавляет чекбоксы к узлам дерева.

Результат:



Для того, чтобы проверить, насколько хорошо работают определенные нами методы для нового компонента:



Код и демо можно глянуть здесь — webix.com/snippet/9f166141

Формы с табами и Многошаговые формы


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

Добавляем табы с помощью Tabview



Tabview component позволяет создать набор компонентов с таббаром, служащим для переключения между ними. В качестве содержимого каждого таба можно использовать отдельный компонент или создать свой собственный лэйаут с помощью свойств rows и cols.

Вот как работает Tabview:

view:"tabview",
/* содержимое элемента */
cells: [
	{
		header:"First tab label",
		body: {
			/* содержимое первого таба */
		}
	},
	
	{
		header:"Second tab label",
		body: {
			rows:[
				{ /* содержимое первого ряда */},
				{ /* содержимое второго ряда */}
			]
		}
	},
	/* и т.д. */
]


Главная идея этого подхода состоит в том, чтобы поместить Tabview с нужными полями внутри формы. Однако, стоит помнить о том, что компоненты, общие для всей формы (например, кнопка Submit или чекбокс «I agree») должны располагаться за пределами Tabview.

Например:

view:"form",
elements:[
	{view:"tabview", height:250,
	 cells:[
		 /* заголовок и содержимое 1-го таба */
		 {header:"Personal Info",
		  body:{
			  rows:[
				  {view:"text", label:"Name", name:"name"},
				  /* еще поля */
			  ]
		 }
		},
		/* заголовок и содержимое 2-го таба */
		{header:"Delivery Details",
		 body:{
			 rows:[
			 /* еще немножко полей */
			 ]
		 }
		}
	]
   }, /* здесь кончается Tabview */
   {view:"button", value: "Submit", width: 150, 
    align:"center", click:submit}     
]


Это все, что вам нужно для создания формы с табами. Ниже приведен результат:



Лучшая часть всей этой истории состоит в том, что вам не нужно писать какой-то дополнительный код, чтобы разные части формы работали как единое целое. Просто поместите Tabview внутрь формы и не забудьте про свойство name для каждого ее элемента.

Кнопка Submit это подтверждает:



Код и демо можно глянуть здесь — webix.com/snippet/79eb2712

В качестве альтернативы табам, вы можете попробовать, например, Accordion.

Создание многошаговой формы с помощью Multiview


Multiview позволяет создавать последовательность элементов и просматривать их один за другим, что позволяет экономить место на экране. Более того, переключение происходит с эффектом анимации! Можно создать табы для переключения между компонентами, но, поскольку нас интересует многошаговая форма, давайте используем кнопки для нашего примера.

В первую очередь нам понадобятся функции для перехода между элементами формы:

function next(){
	var parentCell = this.getParentView().getParentView();
	var index = $$("formCells").index(parentCell);
	var next = $$("formCells").getChildViews()[index+1]
	if(next)
		next.show();
}

function back(){
	$$("formCells").back();
}


Этот код использует значение ID элемента Multiview, так что не забудьте установить его. Что касается кода формы, он практически не изменяется. Нам нужно только изменить содержимое массива elements. Сам компонент Multiview создается схожим образом с элементом Tabview из прошлого примера. На этот раз нам нужно добавить внутрь этого компонента дополнительный ряд, который будет содержать кнопки управления.

Вот как это можно сделать:

 {view:"multiview", id:"formCells", cells: [
	/* 1-й шаг формы */
	{rows:[
		 {/* определение полей */},
		 {cols:[
			 /* кнопки */
			 {}, /* пустой элемент */
			 {view:"button", value:"Next", click:next}
		  ]}
	]},
	
	/* 2-й шаг формы */
	{rows:[
		{/* ещё поля */},
		{cols:[
			/*кнопки*/
			{view:"button", value:"Back", click:back},
			{view:"button", value:"Next", click:next}
		]}
	]},

	/* последний шаг формы */
	{rows:[
		{/* поля... */},
		{cols:[
			/*кнопки*/
	        {view:"button", value:"Back", click:back },
	        {view:"button", value:"Submit", click:submit}
		]}
	]}
]}


Давайте посмотрим на результат:



После нажатия кнопки Next, появится следующая часть формы:



А теперь давайте проверим введенные данные:



Все работает.

Код и демо можно глянуть здесь — webix.com/snippet/39464194

Заключение


Webix позволяет вам создавать практически любые комбинации компонентов. Внутрь формы можно поместить любой виджет или контрол. Если вас не устраивает функционал определенного компонента, можно создать на его основе свой собственный с помощью protoUI и, опять-таки, поместить его в форму. Таким образом, практически ничто не ограничивает вашу фантазию.

Комментарии (13)


  1. Ungla
    13.08.2015 15:34

    Форма с табами разве не жесть?


    1. stannislav
      13.08.2015 16:31
      +1

      Зависит от сложности данных.
      В кровавом интерпрайзе и не такое бывает


    1. kaatula
      14.08.2015 07:32
      +1

      Жесть, но в этом никогда не признаются :)


    1. asave
      25.08.2015 11:16

      Это зависит от формы. Если форма большая и в ней встречаются необязательные поля, которые в 90% случаев не заполняются, то почему бы их не спрятать?


  1. Arceny
    13.08.2015 20:43
    +3

    Что на счет валидаторов данных?


    1. stannislav
      14.08.2015 09:37

      Конкретно для формы, валидация может задаваться как для отдельных инпутов так и для все формы сразу. К примеру

      webix.com/snippet/341e25f4

        view:"form",
        rules:{
          "username": webix.rules.isNotEmpty,
          "password": function(value){ return value.length>3; }
        }
      


      таже есть механизм для задания сообщения о ошибках

      webix.com/snippet/586b93e0
      {view:"text", label:"Username", name:"username", invalidMessage:"Must not be empty"},
      


  1. nos
    13.08.2015 23:54

    спасибо за статью. тоже присматриваюсь к webix. хочу аналитику в «интерпрайзе» на их «datatable» и «pivot» построить.

    столкнулся со сложностями динамического добавления / изменения элементов.

    Вот в форме тоже хотелось бы динамически удалить / добавить элемент но оставить форму «живой»?

    Как насчет такого примера?


    1. stannislav
      14.08.2015 09:50

      Точно также как форма создавалась, могуд добавляться ( и удаляться ) новые элементы

      webix.com/snippet/150b6d58

        $$("myForm").addView({
          view:"text", label:"just added", value:0
        }, 0);
      


  1. SOLON7
    14.08.2015 07:29

    Действительно что насчет валидации ???


    1. nos
      14.08.2015 10:28

      С валидацией там вроде все пучком — и обьявлять можно и динамически валидировать. Вот примеры docs.webix.com/samples/13_form/04_validation
      вот ссылка на доку: docs.webix.com/desktop__data_validation.html

      webix.ui({
          view:"form1",
          elements:[
              { view:"text", label:'Username', name:"login" },
              { view:"text", label:'E-mail address', name:"email"},
              { view:"text", label:'Password', name:"password"},
              { view:"checkbox", labelRight:'I accept terms of use', name:"accept"}
       
          ],
          rules:{
              login: webix.rules.isNotEmpty,
              email: webix.rules.isNumber,
              phone: webix.rules.isEmail,
              accept: webix.rules.isChecked
          }
      });
      


  1. thunderspb
    14.08.2015 14:58

    Видел в новостях, что оно поддерживает twitter bootstrap, однако не очень понятно как. Есть примеры? Просто выглядит интересно и удобно, но я использую темные темы для bootstrap'a…

    И Chart: если примеры реализации timeline с возможностью скроллинга по времени?

    А так, вполне интересный конструктор.


    1. stannislav
      14.08.2015 17:28

      Насколько я представляю, особой интеграции с Bootstrap нет
      Библиотека может работать с бутстрапом на одной странице ( нет конфликтов ) но темы у неё свои.


    1. stannislav
      14.08.2015 17:30

      наверное можно подогнать темы под нужный цвет в скин билдере