Pull to refresh

Формы в Angularjs. Как я обрел любовь

Reading time7 min
Views87K
Мне предстояло в очередной раз сделать это. Казалось бы ничего ужасного, я делал это сотни раз. Но чувство… чувство, что все это неправильно, так не должно быть и должен быть другой выход, не покидало меня. Тогда я еще не знал, что в скором времени мне предстоит встреча, которая навсегда изменит мой мир, откроет глаза и наполнит жизнь смыслом. Смыслом вставать каждое утро, смыслом делать то, что практически перестало доставлять мне удовольствие, смыслом делиться этим чувством с другими.


Течет река...


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

В их числе одна из главных героинь моей повести. Невооруженным глазом видно, что HTML первозданный, подобно алмазу, непрошедшему огранки, был лишен формы. Естественно, долго так продолжаться не могло, и уже 8 ноября 1993 года из недр ювелирной мастерской миру явились первые черты новой формы, которые впоследствии получили свое законное место на скрижалях второго пришествия.

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

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

Давай к сути


Но вернемся к основной линии повествования. Что же стало с формой? Форма начала меняться. С развитием Фронтенда из эдакого языческого портала в мир забраузерной жизни, она стала элементом его убранства, передав свою силу в руки церкви Йаваскрипта. Почему так произошло, одному лишь Моргану Фриману известно, мы же взглянем на факты. А факты таковы, что проверять форму на серверной части продолжали лишь староверы, да иезуиты, плевавшие на стремление человечества к совершенству в условиях невежества заказчика.

Ваш покорный слуга никогда не относил себя ни к тем и ни к другим. Молодой повеса, я жил и радовался жизни. Нужна валидация? Да, пожалуйста, jQuery validation, да хоть сам напишу. Раз за разом одно и то же: email, пароль, имя … email, пароль, имя…email, пароль, дата… И вот словно волчок в сейфе, в моей голове зародилась мысль, которая крутилась и крутилась бесконечно. Теперь, когда мне приходила задача написать обработку формы, меня одолевало чувство будто я индонезийский крестьянин, который вынужден шваброй счищать снег с лобового стекла своего мопеда за неимением дворников, которые по здравому смыслу должны были установить еще на заводе.

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

Но вот однажды в кругу своих друзей-сектантов меня свели с прекрасной девой. Она была молода и только начала выходить в свет. Звали ее, если на русский манер, Анжелой. Сперва она мне показалась странноватой. Больше всего, меня смущало то, что она не пыталась ничего скрывать, а дела все в лоб. Это было дико для моего воспитания. Не знаю, привлекла ли она меня своими манерами или, быть может, на меня оказало влияние то, что я восхищался ее отцом, серьезным авторитетом в наших кругах. Но я захотел узнать Анжелу поближе, благо девушкой она оказалась доступной.

Ну-ну, не тяни


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

Дождались


В общем, это было неописуемо. Она, будто читая мои мысли, делала все, что я только мог пожелать. Хочешь задать стили для нетронутого input и нет? Задавай, она проглотит.

.ng-pristine{
/*Целомудренная форма*/
}
.ng-dirty{
/*Пользованная форма*/
}

Осталось только написать код, который будет применять эти стили. Вот он:

[jsFiddle]
<input type="text" ng-model="example">


Если у кого-то уже встал
вопрос, что насчет валидных-невалидных:

[jsFiddle]
.ng-valid{
/*Правильная форма*/
}
.ng-invalid{
/*Плохая форма*/
}

<input type="email" ng-model="example">


В общем, парни, цепанула. Начал ее обхаживать. И тут она, надо сказать, раскрылась по полной. Я понял, что задание стилей было лишь развлечением для первого свидания. На самом деле, она могла такое, что другим и не снилось. Сделать интерфейс валидации с кастомными сообщениями без единой строчки йаваскрипта? Сделано:

[jsFiddle]
<form name="LovelyForm">
        <input type="email" name="LovelyEmail" ng-model="email"/>
        <span ng-show="LovelyForm.LovelyEmail.$invalid">You break my heart</span>    
</form>

Причем здесь полная аналогия со стилями, то есть в объекте LovelyForm.LovelyEmail определены логические свойства, соответствующие приведенным ранее стилям:

(boolean) LovelyForm.LovelyEmail.$invalid;
(boolean) LovelyForm.LovelyEmail.$valid;
(boolean) LovelyForm.LovelyEmail.$dirty;
(boolean) LovelyForm.LovelyEmail.$pristine;

Самый сок заключается в том, что в Angular из коробки прописаны директивы, дублирующие атрибуты валидации форм HTML5.

[jsFiddle]
<form name="LovelyForm">
        <input type="number" name="LovelyNumber" ng-model="number" min="0" max="10" required/>
        
        <span ng-show="LovelyForm.LovelyNumber.$error.required">Show me your number</span> 
        <span ng-show="LovelyForm.LovelyNumber.$error.min">OMG, so min</span> 
        <span ng-show="LovelyForm.LovelyNumber.$error.max">OMG, too max</span> 
        
        <input type="text" name="LovelyLove" placeholder="I Love U" ng-model="love" ng-pattern="/I love U too/" required />
        
        <span ng-show="LovelyForm.LovelyLove.$error.pattern">What?! Fucking buster!</span> 
        
</form>

Лично у меня это вызвало восторг, поскольку именно такой минимальной гибкости в поем представлении не хватало пресловутому HTML5.

Собственный валидатор


Ну а самое главное то, с какой легкостью Анжела готова принять в свое лоно валидатор созданный вами на стороне. Для этого всего-то и нужно написать соответствующую директиву:

[jsFiddle]
app.directive('mimimi', function() {
    return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl) {
            ctrl.$parsers.unshift(function(mimimi) {
                if (/mimimi/.test(mimimi)) {
                    alert('mimimi');
                    ctrl.$setValidity('mimimi', true);
                    return mimimi.toUpperCase();
                } else {
                    ctrl.$setValidity('mimimi', false);
                    return undefined;
                }
            });
        }
    };
});

<form name="LovelyForm">
        <input type="text" name="LovelyMimimi" placeholder="mimimi" ng-model="mimimi" mimimi/>
        <span ng-show="LovelyForm.LovelyMimimi.$error.mimimi">Mimimi, please</span>
        <span>{{mimimi}}</span>
</form>

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

При использовании директивы ngModel Angular создает для нее экземпляр специального контроллера NgModelController, который в общем-то и отвечает за все эти свойства валидации: $invalid, $valid, $pristine, $dirty, $error. Поэтому при написании валидатора нам необходимо использовать контроллер, который принадлежит ngModel, что мы и делаем:

require:"ngModel"

Теперь функция link, которая вызывается при каких-либо изменениях, будет принимать в качестве параметра ctl контроллер NgModelController.

Дальше мы обращаемся к массиву $parsers объекта NgModelController, который последовательно выполняет заданные функции, передавая в них содержимое input.

Выполняем проверку регулярным выражением. И если все ок, объявляем LovelyForm.LovelyMimimi.$error.mimimi валидным ctrl.$setValidity('mimimi', true). Возвращаемое функцией значение будет передано в родительский $scope, в нашем случае, в переменную mimimi.

Сабмитим


Ну и наконец, мы хотим обработать данные, которые пользователь любезно нам предоставил. С Angular это делается также на раз:

[jsFiddle]
<form name="LovelyForm" novalidate ng-controller="formController" ng-submit="submit()" >
        <input type="text" name="LovelyText" placeholder="Some Text 1" ng-model="text1" required/>
        
        <input type="text" name="LovelyText2" placeholder="Some Text 2" ng-model="text2" required/>
        
        <input type="text" name="LovelyText3" placeholder="Some Text 3" ng-model="text3" required/>
        
        <input type="submit" value="Send Text" ng-disabled="LovelyForm.$invalid">
</form>

function formController($scope){
    $scope.submit=function(){
        alert(angular.toJson($scope.LovelyForm));
    }
}

По сути достаточно одной из двух директив ngSubmit или ngClick. Разница лишь в том, что первую вы указываете в тэге form, вторую на input с атрибутом type=«submit». При этом указанная функция будет выполняться, как при клике по кнопке, так и при нажатии на Enter после ввода в одном из полей.

Разумеется, для того, чтобы предотвратить появление нативных сообщений валидации HTML5, желательно присвоить форме атрибут novalidate. А для того, чтобы выполнение действия submit или click не было возможно, когда форма заполнена с ошибками, используем директиву ngDisabled. Если ngDisabled true, то submit не пройдет.

Married


В общем, к чему это я, мужики. Будьте осмотрительны. Жил я своей жизнью, менял плагины для jQuery как перчатки. А вот как-то раз расслабился, сунул свой нос, а вовремя не вытащил. Теперь у нас вот с Анжелкой детки скоро будут, одностраничные, так что на jQuery я теперь даже смотреть не могу. Но думаю, не один я здесь такой. Спасибо, что выслушали.
Tags:
Hubs:
+37
Comments28

Articles

Change theme settings