RsValidator — очередная JavaScript библиотека для валидации форм

в 10:53, , рубрики: coffee script, html, javascript, валидация, формы

В процессе разработки очередного проекта с довольно большим количеством форм, в который раз возникла проблема валидации, притом как на стороне клиента, так и на сервере. На поиск готовой библиотеки для фронтенда я убил половину рабочего дня, и в общем-то все безрезультатно. На сервере с этим спокойно справляется symfony 2, а вот подходящей JS библиотеки, на удивление, найти не удалось. Либо не было простой возможности для локализации, либо были строгие требования к html разметке, либо ад из кучи data атрибутов…

В общем, решил попробовать быстренько написать свой простенький велосипед… Разумеется, «быстро» затянулось почти на две недели, а «простая» библиотека каким-то образом стала весить почти 30 кб…

Но результат, на удивление, оказался не очень плохим. И даже, как мне кажется, его не стыдно показать общественности.

RsValidator — простой и удобный в использовании валидатор. Достаточно мощный, но при этом не перегруженный лишней функциональностью.

Если заинтересовало, добро пожаловать под кат!

Для простого примера можно рассмотреть ajax форму входа:

<form id="loginForm">
    <input type="text" name="login"
           data-_rule="email, notBlank"
           data-_error='email("en": "Invalid email format", "ru": "Неверный формат email адреса"),
                               notBlank("en": "Please, insert email", "ru": "Пожалуйста, введите ваш email!")'
    />
    <p data-_place="inputEmail"></p>

    <input type="password" name="password"
           data-_rule="email, notBlank"
           data-_error='notBlank("en": "Please, insert password", "ru": "Вы не ввели свой пароль")'
    />
    <p data-_place="inputPassword"></p>

    <input type="checkbox" name="rememberMe" data-_type="bool" /> remember me

    <button type="submit">Sign in</button>
</form>

И немного JS:

var v = new RsValidator();
v.setLocale('en');
v.init();

$('#loginForm').submit(function() {
    if (v.get('loginForm').process()) {
        $.ajax({
            'url': '/login',
            'data': v.get('loginForm').getValue()
            ....
        })
    }

    return false;
});

Пример 1
Кратко о ключевых особенностях:

  1. Библиотека довольно проста в использовании
  2. Независимость от html разметки. Виджеты могут располагаться где угодно, как угодно, и быть чем угодно. Блок сообщений об ошибках тоже может находится в любом месте документа.
  3. Кастомизация и гибкая настройка. Не хотите использовать живую валидацию — пожалуйста, хотите определить свою логики отображения сообщений об ошибках — тоже без проблем. Притом настроить можно и все виджеты сразу, и каждый отдельно.
  4. Колбеки на onError, onValid.
  5. Простая локализация.
  6. Приведение и проверка типа значения. Если вы указали тип int, вы можете быть уверены, что получите именно int.
  7. Легкая расширяемость. Добавить новое правило валидации или тип очень просто.

Далее будет немного скучной теории, посколько у библиотки нету wiki. Но вы можете сразу перейти к примерам!

Установка

Установить можно через bower:

bower install rsvalidator

Разработка ведется с использованием RequireJS, сборка при помощи almond. Так что, если вы используете amd, то достаточно просто прописать библиотеку в зависимости. В противном случае, RsValidator будет доступен глобально.

Требуется jquery.

Начинаем работу

Для начала валидатор необходимо создать:

var v = new RsValidator();
v.init();

Метод init($scope), выполняет базовую инциализацию. Параметр $scopе (jquery объект) определяет область поиска проверяемых виджетов. Для того, что бы он их автоматически подхватил достаточно указать либой из следующих data атрибутов. Это может быть правило валидации _rule, список ошибок _error, пространство имен _namespace, имя виджета _name, или просто _validate=«true».

Если $scope не задан, областью поиска будет $(‘body’)

По умолчания валидация «живая», то есть все проверки и отображение ошибок происходит сразу после изменения значения виджета (это можно поправить в конфиге).

Правила валидации

Задаются в атрибуте data-_rule. Если правил несколько, их можно записать через запятую. Правило может принимать параметры, к примеру: range(0, 10) — проверяет, входит ли число в интервал от 0 до 10
Список правил:

  1. notBlank — проверка на пустоту
  2. email
  3. range(min, max)
  4. equal(«value»)
  5. notEqual(«value»)
  6. length(min, max) — минимальная и максимальная длина слова
  7. arrayLength(min, max) — минимальная и максимальная длина массива (если тип данных указан как массив)
  8. contain(value1, ...) — содержит ли проверяемый массив все параметры переданные в правило
  9. notContain(value1, ....)
  10. pattern(regExpr) — проверка на соответствие регулярному выражению

Привeдение типов

Виджету можно указать к какому типу приводить его значение. Для этого указывается data-_type. Возможные типы:

  1. string
  2. array(type)
  3. int
  4. bool
  5. double

Типизация строгая, то есть если указан тип int, а значением является «123asd», то при проверке будет получена ошибка.

Обратите внимание, что типа number нет, int и double разделены (не знаю, зачем я это сделал…)

Тип array, единственный кто может принимать параметры. Первый параметр это тип, второй — разделитель. По умолчанию тип — string, а разделитель «,».

Тексты ошибок и локализация

Текст ошибок задается в data-_error, в формате: rule(«error text»):

data-_error='notBlank("Вы не ввели свой пароль")'

Если необходимо добавить локализацию, то формат немного изменится:

data-_error='notBlank("en": "Please, insert password", "ru": "Вы не ввели свой пароль")'

Для того что бы задать текущий язык, достаточно вызвать метод setLocale(lang) у валидатора.

Отображение ошибок

По умолчанию, ошибки отображаются в элементах с data-_place равным имени текущего виджета (это поведения меняется в конфиге).

Так же, в зависимости от результатов проверки, виджету повесится соответствующий css success или error.

Пространства имен

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

Виджетом (widget) — называется любой элемент, с которым работает валидатор. Это может текстовый input, checkbox, radio кнопки, textarea, или даже произвольный блок. Главное что бы были заданы необходимые data атрибуты.

У виджетов есть пространство имен. Оно может быть задано через data-_namespace. В одном пространстве имен может лежать несколько виджетов, и соответвенно один виджет может спокойно иметь несколько namespace (задаются через запятую).

Свое пространство имен определяет форма. Таким образом все виджеты находящиеся в форме, автоматически получают пространство имен равным имени формы. Но ничего не мешает виджету в форме задать еще одно (или несколько) пространств через data-_namespace

Именем виджета или формы может является: data-_name=«», name=«», id=«», порядок указан по мере уменьшения приоритета. Если никакое из этих полей не задано — то будет получена ошибка.

В одном пространстве имен не может быть несколько виджетов с одинаковым именем. В разных — пожалуйста. Это и было одной из причин их введения.

JS API

Переходим к самому интересному — api валидатора.

Работа с виджетами

Основной и самый важный метод валидатора это get(selector). Он возвращает коллекцию виджетов, отобранных по селектору. К примеру:

v.get('namespace1')
v.get('namespace1, namespace2')
v.get('namespace1.widgetName, namespace3')
v.get('widgetName')

Как видно, селектором может быть пространство имен (одно или несколько), конкретный виджет в конкретном пространстве, или просто имя виджета…

Но, главное что с полученной коллекцией можно делать много всяких разных вещей!

Коллекция виджетов

Валидация

validate(): array — выполняет проверку всех виджетов и возвращает список ошибок
isValid(): bool — все ли виджеты валидные или нет
process(): bool — выполняет валидацию и отображает ошибки

Получение значения

Тип возвращаемого значения определяется указаным у виджета атрибутом data-_type

val(): mixed — возвращает значение виджета, если он один, или массив, если несколько
getValue(): object — возвращает значения в виде объекта типа: { widget1Name: value, … }

Ображение ошибки

Хотите отрендерить ошибку вне зависимости от статуса валидации? Метод renderError принимает список правил и отображает ошибки для них.

Настройки и конфигурация

Для гибкой конфигурации используется метод setConfig(settings), к примеру:

v.get('namespace').setConfig({
    onError: function(w, e) {
        console.log('At widget ' + w.getName() + ' error!');
    },
    liveValidate: false
});

Возможные настройки:
locale (string) — текущая локаль для коллекции
liveValidate (bool) — использовать ли «живую» валидацию
successClass (string) — css класс который применится к виджету успешно прошедшему валидацию
errorClass (string) — css класс, если возникла ошибка
setStatusClass (bool) — флаг, определяющий, стоит ли вообще задавать эти классы
defaultErrorHandler (bool) — использовать ли обработчик ошибки по умолчанию

и колбэки:
onError: (widget, error) — вылетает при возникновении ошибки валидации
onValid: () — срабатывает, только тогда, когда ВСЕ виджеты в коллекции прошли проверку
onChange: () — срабатывает при изменении статуса

Для добавления коллекции новых правил валидации, есть методы addRule(rule, option), addRules(rules), а для добавления новых сообщениях об ошибках есть addErrorText

С колекцией виджетов разобрались, теперь рассмотрим несколько методов непосредственно валидатора.

AddScope($scope): RsValidator — Добавляет новую область с виджетами.
AddWidget($widgets, namespace = ‘’, $parent = ‘’): WidgetCollection — добавляет к валидатору виджеты.

setConfig(settings) — метод для конфигурации. Во много аналогичен рассмотренному выше (для коллекции виджетов), но с некоторыми отличиями. Теперь колбэки onValid, onError, onChange привязываются к каждому виджету по отдельности.

Ну а теперь примеры!

Github
Сайт

PS К сожалению одного поста не хватит что бы полностью описать все возможности библиотеки. Поэтому к уважаемому хабрасообществу вопрос. Стоит ли дальше развивать библиотеку? Написать нормальную полноценную wiki, сделать больше примеров, дописать тесты… Свободного времени катастрофически не хватает, поэтому жалко тратить его на никому ненужную вещь…

Автор: Nodlik

Источник


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


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js