Живые формы

Большинство форм в web-приложениях имеют довольно простую структуру. Несколько полей, сабмит, часть полей обязательна, часть — нет. Вроде как никаких проблем с ними возникать не может. Я вот тоже так думал, пока мне не пришлось реализовывать форму для CRM-системы. Сказать что форма была сложной — это ничего не сказать. Но мало того, что в ней было несколько десятков полей, они были обязательными/скрытыми в зависимости от выбранных значений в других полях. Я очень намучился, вешая обработчики на каждое из таких полей, и, чтобы обезопасить себя от подобного стресса в будущем, решил написать нечто, что упростило бы эту задачу.

За основу я взял ранее написанную библиотеку expression.js (Я нигде не упоминал её ранее, но на ней основан Just do it!, а так же когда-то по её мотивам я публиковал пост Интерпретатор выражений за 15 минут, короче говоря использую я эту библиотеку давно, вы можете найти её в комплекте плагина, о котором сейчас пойдет речь). Идея плагина очень простая — в специальных атрибутах мы указываем условия видимости/обязательности элемента формы (так же есть возможность вычисления значения по формуле) и ... все, больше мы ничего не делаем. При инициализации плагин прочитает значения этих атрибутов и повесит нужные обработчики на нужные элементы. Например:

<form>
	<div>
		<label>Element 1</label>
		<input name="a" type="checkbox" />
	</div>
	<div>
		<label>Element 2</label>
		<input name="b" type="text" data-visibility="a" />
	</div>
</form>
<script>
	$(document).ready(function() {
		$('form').liveform();
	});
</script>

Здесь текстовое поле b будет отображаться только если отмечен чекбокс a. Но это слишком просто. Более сложный пример:

<form>
	<div>
		<label>Element 1</label>
		<input name="a" type="checkbox" />
	</div>
	<div>
		<label>Element 2</label>
		<select name="b">
			<option value="x">x</option>
			<option value="y">y</option>
			<option value="z">z</option>
		</select>
	</div>
	<div>
		<label>Element 3</label>
		<input name="c" type="text" data-visibility="a or b = 'y'" />
	</div>
</form>
<script>
	$(document).ready(function() {
		$('form').liveform();
	});
</script>

Теперь видимость поля зависит уже от от двух элементов — чекбокса и выпадающего списка. Если чекбокс отмечен, либо в выпадающем списке выбрано значение y, то поле отображается, если нет — оно скрыто.

Причем, поле скрывается вместе с меткой и родительским контейнером. Селектор для родительского контейнера можно задать через параметр inputcontainer. По умолчанию он равен div. Так же можно задать функции скрытия элемента или отметки его как обязательный (параметры visibilityfn и requiredfn соответственно).

Одно выражение можно применить к группе полей. Для этого нужно добавить атрибут data-visibility или data-required на тег fieldset или другой тег, но с атрибутом role="fieldset". Если элемент формы представляет собой несколько чекбоксов или радиобаттонов, то мы делаем следующее:

<form>
	<p>
		<label>Element 1</label>
		<span role="checkboxgroup" data-formula="...">
			<input name="a[]" type="checkbox" value="x" />
			<input name="a[]" type="checkbox" value="y" />
		</span>
	</p>
	<p>
		<label>Element 2</label>
		<span role="radiogroup" data-formula="...">
			<input name="b" type="radio" value="1" />
			<input name="b" type="radio" value="2" />
		</span>
	</p>
</form>

Теперь немного об именах переменных в выражениях. Как можно догадаться из примеров, приведенных выше, это может быть имя элемента формы. Кроме того это может быть ID элемента или индекс в имени элемента. Например, для переменной elementName подходит любой из вариантов:

<input name="elementName" type="text" />
<input id="elementName" type="text" />
<input name="Model[elementName]" type="text" />

Живые примеры можно глянуть тут. Исходники доступны на GitHub.