ASP.NET MVC: кастомизация отображения клиентской валидации с использованием JQuery.Validate.Hooks + Tipsy

в 14:03, , рубрики: .net, asp.net mvc, jquery, Веб-разработка, метки: ,

ASP.NET MVC Framework позволяет очень легко производить как серверную так и клиентскую валидацию «из коробки». Использование DataAnnotations в ваших моделях превращает процесс валидации в максимально простой алгоритм для разработчика. Фреймворк, в свою очередь, может отображать ошибки используя валидацию JQuery, или же в случае более комплексных ситуаций, ошибки могут быть возвращены уже после серверной валидации. Вот пример небольшой модели и соответствующих сообщений валидации в ошибочных полях.

Пример модели с атрибутами DataAnnotation

Отображение стандартных сообщений об ошибках

В данном случае все поля модели являются обязательными, на что указывает атрибут «[Required]». Именно поэтому под каждым из полей отображается сообщение об ошибке. Просто замечательный функционал, но что же здесь не так? Для того чтобы более четко представить себе проблему и заодно узнать об еще одной «фишке» фреймворка попробуем ввести в поле «Price» любой нечисловой символ.
Вывод длинного сообщения об ошибке
Не смотря на то, что мы не указывали никаких дополнительных атрибутов для нашей модели ASP.NET MVC понимает, что поле «Price» имеет числовой тип и потому опять отображает еще более длинное, не очень эстетичное сообщение об ошибке. К тому же чрезмерная его высота приводит к изменениям высоты формы. Это нас не устраивает, поскольку в нашем случае наличие множества таких сообщений, которые то появляются, то исчезают, приведет к скачкам высоты формы, а это негативно повлияет на общий вид страницы.

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

Наша цель заключается в приведении предыдущей формы к следующему виду:

Результат

Начнем с Razor разметки нашей формы.

@model WebUI.ViewModels.LinkViewModel
@using (Html.BeginForm("AddLink", "Links", FormMethod.Post, new { enctype = "multipart/form-data", name = "AddLinkForm", @class = "add-link" }))
{
    <h2>
        <b>Add a new link</b><a href="#">(?)</a></h2>
    <div class="right">
        <div class="fields">
            <div class="close-button" id="hide_form_link">✖</div>
            <div id="cell">
                <div class="text-field name-url">
                    @Html.EditorFor(model => model.Name)
                    @Html.ValidationMessageFor(model=>model.Name, null, new {style="display:none;"})
                </div>
            </div>
            <div id="cell">
                <div class="text-field for-file">
                    @Html.TextBoxFor(model => model.Link, new { @class = "file_1", @type = "file" })
                    @Html.ValidationMessageFor(model => model.Link, null, new { style = "display:none;" })
                </div>
            </div>
            <div id="cell">
                <div class="text-field price-url">
                    @Html.EditorFor(model => model.Price)
                    @Html.ValidationMessageFor(model => model.Price, null, new { style = "display:none;" })
                </div>
            </div>
        </div>
        <div class="button">
            <span class="left-bg"></span><span class="right-bg">Add link </span>
            <input type="submit" name="" />
        </div>
    </div>
    <div class="clearFix">
    </div>
}

Здесь всё стандартно, отмечу лишь несколько деталей:

  • каждый input обернут в дополнительный блок <div id="cell">;
  • сообщения валидации скрываются при помощи атрибута style = "display:none;".

Также есть у нас довольно простой CSS класс .error, который только и всего лишь рисует рамочку вокруг нужных нам input-ов:

.error .text-field input {
    border-color: #d2d9dc;
    box-shadow: inset 2px 2px 6px #EBEBEB, 0 0 4px #ffd9d9, 0 0 0 5px #ffd9d9;
}

Этот CSS класс мы будем применять к блокам-оберткам полей, которые имеют ошибки валидации. Я намеренно не буду приводить все CSS стили, которые используются в примере, поскольку это не повлияет на суть примера, но займет много места.

Для отслеживания результатов валидации каждого поля воспользуемся плагином JQuery Validate Hooks. Приведенный ниже JavaScript код привязывает выполнение функции highlightElement к событию валидации каждого элемента input:

$(function () {
    // Validation
    $('form').addTriggersToJqueryValidate().triggerElementValidationsOnFormValidation();
    $('input').elementValidation(function (element) {
        highlightElement(element);
    });
});

В свою очередь функция highlightElement определяет существование ошибок валидации и в случае их наличия применяет CSS класс .error к блоку, оборачивающему input. В случае отсутствия ошибок – наоборот.

function highlightElement(input) {
    var el = $(input);
    if (el.hasClass('input-validation-error')) {
        el.parents('div.cell, div#cell').addClass('error');
    } else {
        el.parents('div.cell, div#cell').removeClass('error');
    }
}

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

Просто привяжем Tipsy ко всем блокам, в которых находятся элементы формы.

$('form').find("div#cell").find('.text-field').tipsy({ gravity: 'n' });

Параметром «gravity: 'n'» устанавливается положение подсказки внизу элемента.

Осталось сделать последний штрих, а именно указать какой текст нужно отобразить в подсказке. Для этого немного дополним функцию highlightElement:

function highlightElement(input) {
    var el = $(input);
    if (el.hasClass('input-validation-error')) {
        el.parents('div.cell, div#cell').addClass('error');
        //Set Tipsy text
        var fieldDiv = el.parents('div#cell').find('.text-field');
        var text = fieldDiv.find('span.field-validation-error').find('span').text();
        fieldDiv.attr("original-title", text.toString());
    } else {
        el.parents('div.cell, div#cell').removeClass('error');
        //Remove Tipsy text
        el.parents('div#cell').find('.text-field').removeAttr("original-title");
    }
}

Теперь мы считываем сообщение об ошибке из элемента span.field-validation-error который в случае ошибки генерируется автоматически при помощи хелпера

@Html.ValidationMessageFor

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

Автор: sqrter

* - обязательные к заполнению поля