Pull to refresh

AngularJS для привыкших к jQuery

Reading time4 min
Views165K
Original author: Vlad Orlenko
AngularJS — прекрасный фреймворк для построения веб-приложений. У него замечательная документация, снабженная примерами. В обучающих «пробных» приложениях (вроде TodoMVC Project) он очень достойно показывает себя среди остальных прочих фреймворков. По нему есть отличные презентации и скринкасты.

Однако если разработчик никогда ранее не сталкивался с фреймворками, подобными Angular, и пользовался в работе в основном библиотеками вроде jQuery, то ему может быть трудно изменить свой образ мышления. Как минимум, так было со мной, и я бы хотел поделиться некоторыми заметками на эту тему. Может быть, кому-то это будет полезно.

Не библиотека

Первая вещь, которую следует понять про Angular: это совершенно иной инструмент. jQuery — это библиотека. AngularJS — это фреймворк. Когда ваш код работает с библиотекой, он сам решает, когда вызывать ту или иную функцию. В случае же фреймворка вы реализуете обработчики событий, и уже фреймворк решает, в какой момент их вызывать.

Эту разницу легче понять, если подумать над тем, что происходит во время исполнения. Что jQuery делает в рантайме? Практически ничего. Код jQuery вызывается только в ответ на что-то, что произошло в вашем коде — когда сработал триггер какой-либо из функций, вызванный событием DOM.

Angular же на стадии загрузки превращает ваше дерево DOM и код в angular-приложение. HTML-разметка страницы с angular-директивами и фильтрами в ней компилируются в дерево шаблонов, соответствующие области видимости (scope) и контроллеры присоединяются к ним в нужных местах, внутренний цикл работы приложения обеспечивает правильную привязку данных между представлением и моделью. Это реально работающая схема в полном согласии с принципами MVC, обеспечивающая очень чистое разделение между представлением, контроллером и моделью. Если говорить про общий цикл событий, отрисовки страницы и привязки данных, то вы можете считать, что он выполняется непрерывно все время, вызывая при этом код из ваших контроллеров лишь когда это требуется.

image

При каждом обновлении модели (неважно, через асинхронный AJAX-запрос или напрямую через изменение данных из контроллера) Angular перезапускает цикл специальной процедуры $digest, которая обновляет привязки данных и сохраняет всю систему в актуальном состоянии.

Декларативный подход вместо императивного

В отличие от некоторых других библиотек и фреймворков, Angular не расценивает HTML как проблему, которую требуется решать (не буду показывать пальцем). Вместо этого он расширяет их настолько естественным образом, что поневоле задумаешься, почему сам до этого раньше не додумался. Это легче показать, чем объяснить.

Допустим, мы хотим показывать и скрывать некоторый элемент, основываясь на состоянии чекбокса. В jQuery мы бы сделали это как-то так:

<input id="toggleShowHide" type="checkbox">
<div id=”specialParagraph”>
    Этот элемент будет пропадать и возвращаться, когда вы нажимаете на чекбокс
</div>

$(function() {
     function toggle() {
        var isChecked = $('#toggleShowHide).is(':checked');
        var specialParagraph = $('#specialParagraph');
        if (isChecked) {
            specialParagraph.show();
        } else {
            specialParagraph.hide();
        }
    }
    $('#toggleShowHide).change(function() {
        toggle();
    });
    toggle();
});


Обратите внимание на то, что javascript-код здесь воспринимает DOM с точки зрения императивного подхода: возьми этот элемент и его атрибут, посмотри на его значение, сделай так-то и так-то.

Теперь посмотрим на то же самое в терминах Angular:

<input ng-model="showSpecial" type="checkbox">
<div ng-show=”showSpecial”>
    Этот элемент будет пропадать и возвращаться, когда вы нажимаете на чекбокс
</div>

И всё! Кода нет вообще, только лишь чистый декларативный стиль определения привязок и правил. Вот демонстрация этого кода в jsFiddle: jsfiddle.net/Y2M3r

Прямые манипуляции с DOM не просто перестают быть обязательными; можно сказать даже более, их использование в подходе Angular крайне не рекомендуется. Дерево DOM должно быть полностью определено в шаблонах, данные — в моделях и областях видимости, функциональность — в контроллерах, какие-либо нестандартные трансформации — в собственных фильтрах и директивах.

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

Двусторонняя привязка данных

Процесс привязывания значения из DOM к данным модели через контроллер и его область видимости создает самую что ни на есть «привязку» в полном смысле этого слова. Вероятнее всего, вы уже знаете это из документации и примеров, но я просто не могу это не сказать. Это одно из самых сильных первых впечатлений от использования Angular.

<input type="text" ng-model="yourName" placeholder="Введите имя" />
<h1>Hello {{yourName}}!</h1>

Демонстрация: jsfiddle.net/6UnVA/1

Внедрение зависимости

Я выскажусь несколько самоуверенно, но в Angular реализован самый элегантный способ отслеживания зависимостей в мире.

Допустим, у вас есть некоторый источник JSON-данных, обернутый в специальный сервис $resource на стороне Angular.

DataSource = $resource(url, default_params, method_details)
(обратитесь к документации за подробностями)

Любая функция-контроллер, которой требуются эти данные, может включить DataSource в список своих параметров. Это всё, что от нее требуется. Это такая маленькая уличная магия, которая не перестает меня удивлять каждый день при работе с AngularJS. Вам нужно выполнять асинхронные HTTP-запросы из контроллера? Добавьте $http в параметры. Нужно писать в лог консоли? Добавьте $log как аргумент вашей функции.

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

Доступ к данным

Кроме того, что Angular дает вам полную свободу выбора в том, как организовывать данные в модели (можно использовать простые переменные, объекты и массивы в любых сочетаниях), он также предоставляет удобный способ общаться с REST API на сервере. К примеру, мы хотим получать и сохранять записи о пользователях. Вот как может быть организован доступ к ним:

var User = $resource('/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
  user.abc = true;
  user.$save();
});


Angular имеет неплохие предустановки для обычных операций выборки, удаления, получения и изменения данных. А спецпараметры в URL дают возможность настраивать доступ в соответствии с вашими нуждами.

Другие важные моменты, которые здесь остались без внимания — это, например, валидация форм, модульное тестирование (как раз модульное тестирование я лично считаю даже более важным, чем многое из этой статьи — прим. пер.) и библиотека angular-ui. Возможно, в дальнейших постах.
Tags:
Hubs:
Total votes 77: ↑74 and ↓3+71
Comments146

Articles