Тут можно получить информацию
- примеры использования CoffeeScript
- “классовое” ООП с CoffeeScript
- примеры удачных решений структуры алгоритма
- jQuery вместе с CoffeeScript
- микрошаблонизатор на CoffeeScript
- версия кода без комментариев
- аннотации
- версия кода с построчными комментариями
- дополнительные материалы
- пример использования
Рассмотрим следующий код, определяющий класс валидации. Некоторые методы используют jQuery.
В редакторе нет подсветки Coffee, использовал питоновскую.
class validation find: (rules, rule) -> rules = rules.split '|' (rule in rules) validate: (rules) -> $('.form_error').remove() delete @errors_list @fields = {} @data = {} for field, rule of rules @fields[field] = $("input[name=\"#{field}\"]"); @data[field] = @fields[field].val() @validate_field field, @data[field], rules_string unless @errors_list? @data else @show_errors() false show_errors: -> focus_set = false for field, errors of @errors_list messages = [] for error in errors messages.push @lang error @fields[field].before nano templates.form_error, {message: messages.join(' ')} unless focus_set @fields[field].focus() focus_set = true lang: (error) -> [rule,value] = @rule_value error if value? nano lang.errors[rule], {val: value}) else lang.errors[rule] rule_value: (rule)-> x = rule.split '[' if x[1]? if x[1].substr(x[1].length - 1) == ']' x[1] = x[1].substr 0, x[1].length - 1 [x[0],x[1]] min_length: (str,length) -> (str.length >= length) max_length: (str,length) -> (str.length < length) valid_email: (str) -> (/^[\w\d_-]+@+[\w\d_-]+\.+[\w]/i.test(str)) required: (str) -> (@min_length str, 1) min_value: (num,value) -> (num > value) max_value: (num,value) -> (num < value) numeric: (num) -> (/[^\d]/g.test(num)) alpha_numeric: (str) -> (/[^\da-z]/gi.test(str)) trim: (str) -> str.replace /^\s+|\s+$/g, '' integer: (str) -> parseInt(str) parse_rules: (rules) -> rules.split '|' validate_field: (field,str,rules) -> rules = @parse_rules rules for rule_string in rules [rule,value] = @rule_value(rule_string) result = @[rule] str, value unless result in [true,false] # post processing str = @data[field] = result else unless 'required' not in rules and str.length is 0 if result is no @set_error field, rule_string break set_error: (field,rule) -> if @errors_list is undefined @errors_list = {} if @errors_list[field] is undefined @errors_list[field] = [] @errors_list[field].push rule
Каждый из методов этого класса может быть использован сам по себе. Естественно, можно изменять и дописывать собственные методы – вместе с CoffeeScript это легко и занимательно.
Небольшой ликбез. Метод класса – это тоже самое, что функция класса. В JavaScript (и в CoffeeScript тоже, разумеется) доступен после инициализации класса через оператор доступа – точку. Примеры ниже.
Метод find позволяет найти указанное правило в строке определения правил валидации, написанной в духе CodeIgniter. В конкретном проекте, где в качестве бекенда выступил CI, мне было удобно непосредственно экспортировать объект правил в клиент.
Метод validate, принимающий список полей и правил, для каждого элемента формы выполнит очистку данных и проверку соответствия правилам. В случае успешного прохождения валидации метод вернет объект с чистыми данными. В случае обнаружения ошибок метод вызывет брата show_errors() и вернут false. Данные и ошибки сохраняются, как свойства класса. Поэтому они доступны для дальнейшего использования, и по этой же причине они очищаются перед началом.
Метод show_errors вставит сообщения об ошибках рядом с полями формы, и установит фокус (курсор) в первое поле, содержащее ошибку.
Метод lang найдет подходящее сообщение об ошибке, вставит в него значение из правила, если оно есть, и вернет строку.
Метод rule_value вернет значение из правила. Сделано на скорую руку, наверное можно сделать значительно красивее посредством регулярных выражений. Если у вас есть время и понимание – напишите в ЛС или комментарии, проверим и обновим код.
Методы min_length, max_length, valid_email, required, min_value, max_value, numeric и alpha_numeric проводят проверку с соответствующими правилами. Вы легко можете добавить методы.
Как и в CodeIgniter, валидация не только проверяет данные, но и очищает их. В данном классе это делают методы trim и integer.
Элементарный метод parse_rules принимает строку правил, отформатированную в духе CodeIgniter, и преобразует ее в массив.
Метод validate_field, принимает для обработки имя поля, строку и правила, производит обработку строки и проверку на соотвествие правилам, после чего помещает ее в локальный объект данных для последующего использования.
Метод set_error просто запоминает ошибку.
Теперь версия кода с построчными комментариями.
class validation find: (rules, rule) -> # преобразует строку в массив, разделив по символу | rules = rules.split '|' # вернет результат проверки - есть ли rule в массиве rules (rule in rules) validate: (rules) -> # удалит все отбражаемые сообщения об ошибках - с классом .form_error $('.form_error').remove() # удалит список ошибок delete @errors_list # очистит локальный список ссылок на поля формы @fields = {} # создает (очищает) локальный объект данных @data = {} # пройдет в цикле все правила for field, rule of rules # сохранит ссылку на поле формы (просто для быстродействия) @fields[field] = $("input[name=\"#{field}\"]"); # извлечет данные из поля формы @data[field] = @fields[field].val() # проведет валидацию @validate_field field, @data[field], rules_string # если локальный список ошибок не существует unless @errors_list? # вернет данные @data else # вызовет метод для отображения сообщений об ошибках @show_errors() # вернет false false show_errors: -> # отметит, что фокус еще никуда не устанавливался focus_set = false # обойдет в цикле объект с ошибками for field, errors of @errors_list # тут у нас будут сообщения об ошибках messages = [] for error in errors # преобразует сообщения об ошибках в читаемый вид messages.push @lang error # перед каждым полем вставит сообщения об ошибках, связанные с этим полем @fields[field].before nano templates.form_error, {message: messages.join(' ')} # поставит фокус в первое поле, с которым связаны сообщения об ошибках unless focus_set @fields[field].focus() focus_set = true lang: (error) -> # получит значение из правила, если оно есть [rule,value] = @rule_value error if value? # обработает строку со значением nano lang.errors[rule], {val: value}) else # если значения нет - вернет языковую строку, как есть lang.errors[rule] rule_value: (rule)-> # обработает конструкцию вида min_length[3] x = rule.split '[' if x[1]? if x[1].substr(x[1].length - 1) == ']' x[1] = x[1].substr 0, x[1].length - 1 [x[0],x[1]] min_length: (str,length) -> # вернет true, если длина строки больше или равна заданному значению (str.length >= length) max_length: (str,length) -> # вернет true, если длина строки меньше заданного значения (str.length < length) valid_email: (str) -> # вернет true, если строка соответствует паттерну (/^[\w\d_-]+@+[\w\d_-]+\.+[\w]/i.test(str)) required: (str) -> # вернет true, если строка не пустая (@min_length str, 1) min_value: (num,value) -> # вернет true, если число больше заданного (num > value) max_value: (num,value) -> # вернет true, если число меньше заданного (num < value) numeric: (num) -> # вернет true, если строка содержит только цифры (/[^\d]/g.test(num)) alpha_numeric: (str) -> # вернет true, если строка содержит только цифры и буквы (/[^\da-z]/gi.test(str)) trim: (str) -> # очистит строку от ведущих и замыкающих пробельных символов str.replace /^\s+|\s+$/g, '' integer: (str) -> # приведет в целочисленный вид parseInt(str) parse_rules: (rules) -> # преобразует строку правил в массив rules.split '|' validate_field: (field,str,rules) -> # преобразует строку правил в массив rules = @parse_rules rules # в цикле исследует все предоставленные правила for rule_string in rules # получит значение из правила, если оно есть [rule,value] = @rule_value(rule_string) # вызовет колбек для обработки или проверки result = @[rule] str, value # если результат обработки - что-то, кроме false или true # - значит была обработка, а не проверка unless result in [true,false] # перепишем результат str = @data[field] = result # если не просили пустую строку, но ничего не получили else unless 'required' not in rules and str.length is 0 if result is no # ловим ошибку @set_error field, rule_string # а смысл дальше искать? # Если хотите - уберите эту строку, # мне нужна была полная аналогия с CI break set_error: (field,rule) -> # создаст объект ошибок, если его нет if @errors_list is undefined @errors_list = {} # создаст ветку об ошибках конкретного поля, если его еще нет if @errors_list[field] is undefined @errors_list[field] = [] # запомнит сообщение об ошибке @errors_list[field].push rule
Используются сообщения об ошибках, хранящиеся в объекте, как показано ниже.
lang = errors: min_length: 'Недостаточная длина, нужно как минимум {val} симв.' max_length: 'Слишком длинная строка, допускается максимум {val} симв.' min_value: 'Слишком малое значение, нужно как минимум {val}.' max_value: 'Слишком большое значение, нежно не более {val}.' numeric: 'Допускаются только цифры.' alpha_numeric: 'Допускаются только цифры и буквы латиницы.' valid_email: 'Нужно указать правильный адрес электронной почты.' required: 'Здесь необходимо указать данные.'
Для обработки сообщений об ошибках используется популярный минималистичный JS-шаблонизатор, вот его код, уже на CoffeeScript
_nano_regex = /\{([\w\.]*)\}/g nano = (template, data) -> template.replace _nano_regex, (str, key) -> keys = key.split(".") value = data[keys.shift()] $.each keys, -> value = value[this] (if (value is null or value is `undefined`) then "" else value)
Оффтоп. Вот вам небольшой подарок за то, что вы читаете эти строки:
add_quotes = (str) -> (if str? then str.replace /"/g, """ else '')
Использование
Допустим, у нас есть такие поля в форме
<label>Имя</label> <input type=”text” name=”name” value=”Василий”> <label>Фамилия</label> <input type=”text” name=”surname”> <label>Электропочта</label> <input type=”text” name=”email”>
Тогда мы можем задать правила для валидации и вызвать обработку по сабмиту формы.
rules = name: 'trim|required|min_length[2]|max_length[255]' surname: 'trim|max_length[255]' email: 'trim|required|valid_email|max_length[255]' validation = new validation $('body').on 'submit', 'form', => data = validation.validate rules if data isnt off # отправляем их аяксом на сервер else # ошибки приключились. В принципе, можем больше ничего не делать – появятся сообщения об ошибках и даже курсор встанет в нужное поле
Спасибо за внимание и удачи вам!
ссылка на оригинал статьи http://habrahabr.ru/post/184344/
Добавить комментарий