Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kharkiv.js#2 - Валидация данных на клиенте (JavaScript)

Kharkiv.js#2 - Валидация данных на клиенте (JavaScript)

Мотивация валидации данных на клиенте, почему валидация мигрирует с сервера на клиент. Простые примеры на Backbone.js и Angular.js, валидация структуры с помощью contract.

Max Klymyshyn

June 06, 2013
Tweet

More Decks by Max Klymyshyn

Other Decks in Technology

Transcript

  1. Здрасьте, это я Background ‣ Lead both-end developer @oDesk Inc.

    ‣ Front-end consultant @Helios ‣ Conferences organizer Tuesday, June 25, 13
  2. В теме? Background ‣ Любовь в основном с Angular.js ‣

    Очень стараюсь смотреть на вещи трезво, а не инженерно ‣ Активно учавствую в украинских Python и JavaScript движениях Tuesday, June 25, 13
  3. ЧЕ? Topic ‣ Концептуально валидация нужна для работы с корректными

    данными внутри ПО ‣ Мотивация валидации на клиенте намного сложнее: это UI, время отклика интерфейса, комфорт в разработке, субъективное представление об интерфейсе Tuesday, June 25, 13
  4. Начнем издалека Поначалу валидация была очень проста (CGI, Perl) $success

    = $dbh->do( "INSERT INTO $serverTabl(". "name,author,url,keyword1,keyword2,keyword3,". "keyword4,keyword5) VALUES(?,?,?,?,?,?,?,?)", undef,$name,$author,$url,$keyword[0],$keyword[1], $keyword[2],$keyword[3],$keyword[4]); if($success != 1) { return "Sorry, the database was unable to add your entry. ". "Please try again later."; } else { return; } Tuesday, June 25, 13
  5. Adobe Flash, Adobe Flex, MooTools, jQuery etc. После появления разного

    рода фреймворков все стало относительно просто: ‣ Валидацию начали аккуратно встраивать на серверных фреймворках (Zend Forms, Struts, Adobe Flex, Django) ‣ На клиенте начали “вручную” создавать довольно навороченные валидации с кошмарным кодом. Tuesday, June 25, 13
  6. История ‣ Требует ресурс сервера, неприятно если контекст запросов достается

    из БД (сессии, контент страницы т.п.) ‣ Плохое время отклика - перезагрузки всей страницы ‣ Stateless-природа HTTP вынуждает хранить контекст всей страницы при сложном data- flow Если client-side валидация так хороша - почему от нее отказались? Tuesday, June 25, 13
  7. История ‣ Плохой UX - большое время загрузки страницы ‣

    AJAX может сильно помочь, но существенно усложнит логику на сервере и клиенте С точки зрения UX Tuesday, June 25, 13
  8. Stupid. “Captcha Makes It Impossible For The Blind To Sign

    Online Petition Supporting Copyright Treaty For The Blind” Someone from Twitter Не надо переусердствовать Tuesday, June 25, 13
  9. Глаз ‣ Человеческий глаз видит 10-12 отдельный изобажений в секунду

    ‣ Все что меняется быстрее 50ms - незаметно ‣ The memory-prediction framework - мозг строит прогноз-ожидание (via Jeff Hawkins) Немного о высоком Tuesday, June 25, 13
  10. Итого ‣ Сделать зрению комфортно. ‣ Удобно программировать ‣ Не

    нагружать сервер дополнительной логикой Короче, чего мы хотим Tuesday, June 25, 13
  11. jQueryValidation <form class="cmxform" method="get"> ... <input id="cname" name="name" minlength="2" type="text"

    required/> <input id="cemail" type="email" name="email" required/> $(".selector").validate({ invalidHandler: function(event, validator) { var errors = validator.numberOfInvalids(); if (errors) { var message = errors == 1 ? 'You missed 1 field. It has been highlighted' : 'You missed ' + errors + ' fields.'; $("div.error span").html(message); $("div.error").show(); } else { $("div.error").hide(); } } }); Tuesday, June 25, 13
  12. Давайте вернемся в 2013 год Backbone.js ‣ В моделях Backbone.js

    есть метод validate, а также при вызове метода set модели можно ловить change:property ‣ Есть плагин backbone.validation, позволяет в декларативном стиле задавать правила Tuesday, June 25, 13
  13. Backbone.js Backbone.js var SomeModel = Backbone.Model.extend({ validation: { 'name': {required:

    true}, 'address.street': {required: true}, 'address.zip': {length: 4}, 'age': {range: [1, 80]}, 'email': {pattern: 'email'}, 'someAttribute': function(value) { if(value !== 'somevalue') return 'Error message'; } }}); var Person = Backbone.Model.extend({ // If you return a string from the validate function, // Backbone will throw an error validate: function( attributes ){ if( attributes.age < 0 && attributes.name != "Dr Manhatten" ){ return "You can't be negative years old"; } } Tuesday, June 25, 13
  14. Но есть проблемы Backbone.js ‣ Нужно имплементить отображение на уровне

    view ‣ Интерактивное отображение ошибок вынуждает писать больше кода ‣ В случае дочерних view сложность кода сильно возрастает (ловить event-ы) Tuesday, June 25, 13
  15. Angular.js Angular.js ‣ Хорошие возможности валидации задаются декларативно из коробки

    - email, number, regexp. Красота, которая из коробки в html5 ‣ Кастомная валидация имплементится в виде директив, что обеспечивает надежный уровень изоляции ‣ Все валидируется “на лету”, к полям автоматически добавляются соотв. классы в случае ошибки (или ошибок) Tuesday, June 25, 13
  16. Декларативненько на борту Angular.js ‣ Input types: email, number, url

    ‣ ngPattern – проверерка по regexp-у ‣ ngRequired, ngMinlengh, ngMaxlength ‣ ngList – преобразует строку с разделителем в массив (по умолчанию разделитель - запятая) ‣ ngTrim – пробелы в начале и конце строки игнорируются Tuesday, June 25, 13
  17. А если AJAX? Angular.js ‣ Сложность резко возростает ‣ Нужно

    имплементить директиву ‣ и хорошо понимать что происходит в процессе валидации Tuesday, June 25, 13
  18. Angular.js userinfo.directive('ajaxValidate', ['$http', function($http) { return { restrict: 'A', require:

    'ngModel', link: function(scope, elem, attrs, ctrl) { var url = attrs.ajaxValidateUrl; var isEnabled = scope[attrs.ajaxValidate]; var messageId = attrs.name + "_invalid"; var actions = { error: function (value, data) { ctrl.$setValidity('ajaxvalidate', false); scope[messageId] = data.errors.value; return undefined; }, success: function (value, data) { ctrl.$setValidity('ajaxvalidate', true); return value; } }; ... Tuesday, June 25, 13
  19. Angular.js ... ctrl.$parsers.push(function(value) { scope[messageId] = ''; if (isEnabled !==

    true) return; ctrl.$setValidity('ajaxvalidate', false); elem.attr("readonly", "readonly"); // doing HTTP request to validate value $http.post(url, {value: value}) .success(function(data) { elem.removeAttr("readonly"); return actions[data.action](value, data); }) .error(function (data) { elem.removeAttr("readonly"); alert("Something went wrong..."); }); }); } }; }]); Tuesday, June 25, 13