Главная страница   /   6.2. Валидация на стороне клиента (ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

Джеффри Палермо

6.2. Валидация на стороне клиента

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

Построение этого сценария с нуля чаще всего неоправданно, потому что многие фреймворки валидации на стороне клиента находятся в стадии разработки в течение нескольких лет. В этом случае связывание клиентской и серверной валидации без повторения большого объема кода становится очень важной задачей. В ASP.NET MVC потенциальное дублирование значительно снижается.

ASP.NET MVC включает поддержку библиотеки JQuery Validate для осуществления валидации на стороне клиента. Еще одна новая особенность MVC – поддержка ненавязчивой валидации на стороне клиента. Она соотносит элементы ввода с атрибутами данных, которые используются в скриптах. В ASP.NET MVC 2 валидация на стороне клиента была навязчивой, то есть специальный скрипт связывался с элементами ввода в процессе рендеринга.

В этом пункте мы изучим новые функции валидации на стороне клиента в ASP.NET MVC. Для начала рассмотрим простой пример, а затем разберем два способа модификации: использование RemoteAttribute и создание пользовательских валидаторов JQuery.

Включение валидации на стороне клиента

Чтобы начать работу с валидацией на стороне клиента, необходимо добавить в наши страницы скрипты jQuery Validate. Добавим их в макет страницы.

<script src="@Url.Content("~/Scripts/jquery-1.6.1.min.js")"
	type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")"
	type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"
	type="text/javascript"></script>

Так как каждая новая библиотека JavaScript опирается на другие, важно, чтобы файлы были включены в правильном порядке. Сначала мы регистрируем библиотеку JQuery, затем – плагин Validate и вспомогательные скрипты для ненавязчивой валидации.

Когда клиентские библиотеки включены в основной макет, мы можем включить ненавязчивую валидацию. Это может быть сделано на уровне приложения в файле Web.config или для определенных запросов с помощью двух вспомогательных методов.

<appSettings>
	<add key="ClientValidationEnabled" value="true"/>
	<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>

Методы EnableClientValidation и EnableUnobtrusiveJavaScript просто включают флаги в ViewContext. Чтобы скрипты подключились корректно, они должны быть размещены перед методом BeginForm.

@{Html.EnableClientValidation();}
@{Html.EnableUnobtrusiveJavaScript();}
@using (Html.BeginForm("Edit", "Home")) {
	@Html.EditorForModel()
	<button type="submit">Submit</button>
}

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

<input class="text-box single-line" data-val="true"
	data-val-required="The Company Name field is required."
	id="CompanyName" name="CompanyName" type="text" value="" />

Эти метаданные обрабатываются библиотекой JavaScript jquery.unobtrusive и включаются в логику проверки плагина JQuery Validate.

Установив пользовательские валидаторы, проверим валидацию на стороне клиента и отправим форму с пустым полем для названия компании. В результате она не отправляет запрос на сервер, что показано на рисунке 6-4.

Так как валидация на стороне сервера все еще включена, мы можем быть уверены, что валидация будет выполнена даже в браузерах без JavaScript. ASP.NET MVC поддерживает пользовательские валидаторы и плагины для серверных и клиентских сценариев.

Рисунок 6-4: Валидация на стороне клиента

Использование RemoteAttribute

В ASP.NET MVC 3 появился новый атрибут валидации - RemoteAttribute. Если включить его в свойство модели, jQuery Validate будет отправлять HTTP-запрос к определенному методу действия для осуществления проверки на стороне сервера. Результат будет пересылаться обратно клиенту, и сообщение об ошибке будет выводиться еще до отправки формы. Это хороший способ обеспечить быструю обратную связь для сценариев, которым необходима обработка на стороне сервера.

public class UsingRemote
{
	[Required]
	[Remote("IsNumberEven", "Home", ErrorMessage = "The number is odd.")]
	public int EvenNumber { get; set; }
}

Строка 4: Применение RemoteAttribute к свойству модели

Этот атрибут указывает, какой контроллер и какое действие должен вызвать клиентский скрипт, а также содержит сообщение об ошибке. После того, как пользователь изменит значение в элементе ввода, клиентский скрипт отправить имя элемента и значение к методу действия. Имя параметра действия должно совпадать с именем элемента ввода.

public JsonResult IsNumberEven(int evenNumber)
{
	return Json(evenNumber%2 == 0, JsonRequestBehavior.AllowGet);
}

Это действие проверяет, является ли число четным и возвращает булево значение в JsonResult. Булево значение указывает на результат валидации - естественно, true означает, что валидация прошла успешно. Этот атрибут можно использовать очень широко – для поиска соответствий допустимых значений в базе данных или выполнения сложных сценариев. Если возможно отправлять несколько HTTP-запросов во время заполнения формы, RemoteAttribute - это отличный способ сделать интерфейс более быстрым и удобным. Если из-за запросов снизится производительность, можно использовать пользовательские валидаторы на стороне клиента.

Создание пользовательских клиентских валидаторов

Когда атрибут валидации поддерживает интерфейс IClientValidatable, DataAnnotationsModelMetadataProvider (и любые производные от него, такие как наш ConventionProvider) передаст платформе инструкцию генерировать атрибуты данных для связанных HTML-элементов. Используя этот механизм, мы можем настроить валидацию на стороне клиента с помощью собственного JavaScript кода. Он эффективен для отдельных сценариев, когда валидаторов библиотеки JQuery Validate недостаточно.

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

public interface IClientValidatable
{
	IEnumerable<ModelClientValidationRule> GetClientValidationRules(
		ModelMetadata metadata, ControllerContext context);
}

Метод получает в качестве параметра метаданные модели, так что мы можем определить правило для конкретного свойства модели, которое мы проверяем. В этом примере мы включим отформатированное отображаемое имя в сообщение об ошибке. Для максимальной расширяемости, метод возвращает интерфейс IEnumerable<ModelClientValidationRule>, и то, что он возвращает только одно правило, имеет смысл. Таким образом, именно тот атрибут валидации, который выполняет проверку хронологии дат на стороне сервера, будет реализовывать этот интерфейс. Реализация показана в следующем листинге.

Листинг 6-3: Реализация IClientValidatable
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
		ModelMetadata metadata, ControllerContext context)
{
	var rule = new ModelClientValidationRule
	{
		ErrorMessage = GetErrorMessage(metadata.ContainerType,
			metadata.GetDisplayName()),
		ValidationType = "later",
	};
	rule.ValidationParameters
		.Add("other", "*." + _otherDateProperty);
	yield return rule;
}

Строки 6-7: Составление сообщения об ошибке

Строка 8: Тип валидации соответствует валидатору JQuery

Строки 10-11: Добавление параметра, который будет передан в валидатор

ModelClientValidationRule - это простой класс, который имеет три свойства. ErrorMessage будет отображаться в случае сбоя валидации, ValidationType - это имя валидатора (к которому мы обратимся на следующем этапе), а ValidationParameters представляет собой таблицу IDictionary <string, Object> с параметрами, которые мы можем передавать клиентскому скрипту. В листинге 6-3 мы используем отображаемое имя свойства в сообщении об ошибке (строки 6-7). Тип валидации - "later" - имя JQuery валидатора, который мы запишем следующим (строка 8). Мы также добавляем к списку параметров имя otherDateProperty, с которым будем проводить сравнение (строки 10-11). Звездочка в имени свойства нужна, чтобы мы могли найти правильное свойство в крайнем случае, если этот HTML-элемент будет представлен в иерархической форме, которая выводит список содержащей модели.

С помощью IClientValidatable ASP.NET MVC представит правильные атрибуты для ненавязчивой валидации на стороне клиента, используя JQuery Validate. Теперь осталось два этапа: написать валидатор JQuery Validate и добавить в него атрибуты ненавязчивой валидации.

Мы написали упрощенный код JavaScript для добавления валидатора, который будет проверять, что одна дата более поздняя, чем другая. Чтобы провести сравнение, он использует объект JavaScript Date. Value – это значение элемента ввода, который мы проверяем, а параметр params - другой элемент ввода, который мы определили в атрибуте валидации:

$.validator.addMethod("later", function (value, element, params) {
	return new Date(value) > new Date($(params).val());
});

Интересно то, как все элементы взаимосвязаны. Это показано в следующем листинге.

Листинг 6-4: Пользовательский адаптер
// JavaScript source code
function setValidationValues(options, ruleName, value) {
	options.rules[ruleName] = value;
	if (options.message) {
		options.messages[ruleName] = options.message;
	}
}
function getModelPrefix(fieldName) {
	return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}
function appendModelPrefix(value, prefix) {
	if (value.indexOf("*.") === 0) {
		value = value.replace("*.", prefix);
	}
	return value;
}
$.validator.unobtrusive.adapters
	.add("later", ["other"], function (options) {
		var prefix = getModelPrefix(options.element.name),
			other = options.params.other,
			fullOtherName = appendModelPrefix(other, prefix),
			element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];
		setValidationValues(options, "later", element);
});

Этот скрипт использует jquery.validate.unobtrusive.js - библиотеку jQuery Validate Unobtrusive, которая включена в ASP.NET MVC. Это JQuery плагин, который был разработан Microsoft специально для этой платформы, хотя его использование и не ограничивается исключительно проектами ASP.NET MVC. Код в листинге 6-4 не использует этот плагин, но он использует те же встроенные функции, что и плагин. Если вы загляните в jquery.validate.unobtrusive.js (желательно, чтобы вы работали со пользовательскими клиентскими валидаторами), вы увидите, что они идентичны.

Так что же делает этот скрипт? Библиотека jquery.validate.unobtrusive.js умеет подключать ненавязчивые атрибуты данных, которые генерирует ASP.NET MVC, к правилам JQuery Validate, используя адаптеры. Ранее мы создали правило JQuery Validate, здесь мы создаем адаптер. Библиотека выполняет все остальное.

Библиотека jquery.validate.unobtrusive.js содержит встроенные адаптеры, которые очень легко использовать. В большинстве случаев нам не придется писать код. Мы используем пользовательский валидатор, потому что нужно изменить параметр, который отправляется в правило. Библиотека jquery.validate.unobtrusive.js уже содержит адаптеры для нескольких общих правил - тех, которые включены в ASP.NET MVC. Она также содержит вспомогательные методы для большинства правил, которые мы будем создавать. Например, она сама подключает RemoteAttribute – нам не нужно ничего настраивать.