Angularjs — Как это работает (angular.js)…


Содержание

Скринкаст по Angular

Angular – одна из самых популярных библиотек для создания сложных Frontend-приложений.

Однако, успешная разработка на нём требует хорошего понимания концепций, на которых он построен.

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

Его записал Степан Суворов, ведущий наших курсов по Angular, который разрабатывает и преподает этот фреймворк примерно столько, сколько он существует.

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

Команда Angular выпустила инструменты, упрощающие переход с AngularJS на Angular

Команда разработчиков JS-фреймворка AngularJS выпустила два пользовательских «помощника» — ngMigration Assistant и Forum. Инструменты позволяют узнать, какой переход с AngularJS на Angular является верным, как максимально упростить процесс и избежать ошибок.

ngMigration Assistant

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

Ниже — пример использования ngMigration Assistant для приложения AngularJS phone catalog. С помощью команды ngma , прописанной в директории, выполняется анализ и прописываются рекомендации.

Вначале инструмент показывает статистику имеющихся данных, а после — этапы подготовки к миграции на Angular.

ngMigration Forum

В новом сообществе ngMigration Forum собрана актуальная информация о путях миграции и инструментах, обеспечивающих переход с AngularJS на Angular. ngMigration Forum — место для обмена опытом, решения проблем и вопросов фреймворк-экспертам.

Последнее обновление Angular 6.1 вышло в конце июля 2020 года. В Angular была добавлена поддержка TypeScript 2.8 и 2.9, а также возможность настройки роутера на запоминание и восстановление положения прокрутки.

10 преимуществ использования фреймворка Angular.js при разработке веб-приложений

Сегодня разработку одностраничных приложений сложно представить без Angular.js. Давайте вместе разберемся, что это за «фрукт» и какие у него преимущества.

Во-первых, что такое Angular.js фреймворк? Это open source-фреймворк (не библиотека!), который позволяет создавать популярные сегодня одностраничные приложения. После запуска в 2009 году Angular.js быстро набрал популярность и не собирается сдавать позиции — он остается самым востребованным JavaScript-фреймворком на GitHub (в топе как по форкам, так и по количеству «звезд»).

Ниже мы перечислили исчерпывающие причины, почему стоит выбрать AngularJS.

1. Большое комьюнити

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

2. Декларативный стиль кода

При создании шаблонов в Angular.js применяется декларативная парадигма программирования. Это делает код более легковесным, облегчает его чтение и поддержку, так как описывается необходимый конечный результат, а не все шаги по его достижению. Например, сравните фрагменты кода на JavaScript:

3. Использование директив

В качестве языка шаблонов в Angular.js используется HTML. Он расширяется с помощью директив, которые добавляют в код сведения о требуемом поведении (например, о необходимости загрузить определенный модуль сразу после загрузки страницы). Директивы позволяют вам сконцентрироваться на проработке логики и работать более продуктивно. Их можно использовать повторно, что также повышает читабельность кода.

4. Высокая скорость разработки

При правильном подходе с помощью Angular.js можно быстро разрабатывать даже большие приложения.

5. MVC из коробки

В AngularJS используется схема MVC, разделяющая логику, представление и данные приложения:

Это позволяет создавать одностраничные веб-приложения (Single Page Application). В Angular.js имеется служба $http, которая обеспечивает взаимодействие с удаленными HTTP-серверами с помощью XMLHttpRequest или JSONP. При передаче объекта JavaScript на сервер он будет автоматически преобразован в строку JSON. После получения ответа служба также попытается преобразовать полученную строку JSON в JavaScript. Используя службу $http можно создать собственную службу с полным контролем над обработкой URL и данных.

6. Полезные фичи для SPA

Angular.js для вебприложений – это как вода для рыб. Трудно представить, чтобы они могли существовать друг без друга. Например, Angular.js предоставляет возможности по работе с валидацией форм. Если на странице используются формы, FormController записывает их состояние. Используя эту информацию, мы можем задавать поведение HTML-элементов в UI (например, скрыть кнопку «Очистить форму», если пользователь еще не начал вводить данные в форму). Для обработки ошибок в Angular.js предусмотрены встроенные валидаторы (required, ng-required, ng-minlength, ng-pattern и другие), но при необходимости мы также можем создавать собственные. Сообщения об ошибках можно выводить как для всей формы, так и для ее отдельных полей.

Шаблоны или темплейты в Angular.js представляют собой HTML-код, дополненный элементами и атрибутами Angular.js. Фреймворк дополняет шаблон информацией из модели, чтобы показать пользователю динамическую страницу. Для обработки данных и форматирования значений, полученных от модели, используются фильтры. Они позволяют показать нужные данные пользователю без необходимости вносить изменения в исходные данные.

7. Модульность

В Angular.js можно организовывать приложения из отдельных модулей. Такие модули могут как зависеть друг от друга, так и быть автономными. Например, в последнем случае модуль входа через Facebook можно использовать сразу в нескольких частях приложения, скажем, на странице входа и на странице оформления заказа. А благодаря встроенному механизму внедрения зависимостей Angular.js сам распознает ситуацию, когда нужно предоставить вспомогательные объекты, предоставляет их и связывает объекты между собой.

8. Наличие готовых решений

Что важно, для Angular.js существует огромное количество готовых решений, которые позволяют решать довольно разнообразные задачи, используя уже готовые модули. Например, существует несколько модулей для роутинга самый популярный из которых ui-router, так же есть различные модули для работы с таблицами ui-grid, ng-table и много других.

Из-за отсутствия жесткой структуры проекта в AngularJS можно создавать приложения с достаточно разнообразной структурой. Также вы можете использовать AngularJS для мобильной разработки (разумеется, речь идет о создании так называемых гибридных приложений). Как использовать Angular.js фреймворк в этих целях можно почитать здесь.

9. Двустороннее связывание данных

В Angular.js применяется двустороннее связывание: любые изменения в пользовательском интерфейсе сразу же отражаются на объектах приложения и наоборот. Фреймворк сам следит за событиями браузера, изменениями модели и действиями пользователя на странице, чтобы сразу обновлять нужные шаблоны. При этом в коде JavaScript не требуется хранить ссылки на DOM-элементы и явно ими манипулировать. Мы просто описываем необходимый результат в терминах состояния модели, и нам не нужно использовать низкоуровневые конструкции.

10. Простота тестирования

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

Несмотря на вышеупомянутые особенности AngularJS, у него есть и несколько недостатков:

  1. Сложность освоения. Трудности обычно возникают у тех, кто раньше использовал библиотеку jQuery, ведь в отличие от Angular.js она полагается на выполнение манипуляций с деревом DOM.
  2. Замедление работы при использовании более 2000 вотчеров (или слушателей событий).
  3. Отсутствие обратной совместимости со второй версией. Разумеется, вы можете начать подготовку своего кода к миграции уже сейчас, но гарантий, что она пройдет гладко, нет.

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

Нужен MVP, разработка под iOS, Android или прототип приложения? Ознакомьтесь с нашим портфолио и сделайте заказ уже сегодня!

Начало работы с AngularJS


AngularJS это JavaScript фреймворк, который расширяет HTML.

Здесь мы рассмотрим несколько простых примеров использования AngularJS. Для лучшего понимания, возможно, вы заходите взглянуть на AngularJS Book от Chris Smith или ng-book от Ari Lerner.

Чтобы начать работу с AngularJS, нам нужна HTML страница с тремя вещами:

1) Загрузить angular.js

Нам нужно загрузить файл angular.js с одного из CDN или с локального диска.

Если вы хотите загрузить его с Google CDN, тогда добавьте в HTML такой код:

Если хотите использовать Cloudflare CDNjs, тогда такой:

Также вы можете скачать файл angular.min.js, загрузить его на ваш сервер и подключить вот так:

В примерах выше я использовал версию 1.4.2 AngularJS, но ко времени, когда вы будете читать эту статью, у Angular может выйти новый релиз, и, возможно, вы захотите использовать новую версию.

2) Добавить ng-app

Добавьте ng-app к одному из элементов на вашей странице. Все, имеющее этот элемент, будет рассматриваться как часть AngularJS кода. Мы можем добавить это к элементу html , body , или даже div , как это сделано в нашем первом примере.

3) Добавить выражение AngularJS.

AngularJS имеет различные элементы. Выражение (expression) это фрагмент кода, помещенный в << >> . Он может содержать ограниченный набор выражений JavaScript.

Теперь мы подошли к нашему первому примеру. Еще даже до написания Hello

Hello World с AngularJS

В нашем самом первом примере выражение это просто фиксированная строка. Ничего особенного. Даже немного оскорбительно.

И результат — Hello World .

Простое выражение AngularJS

В нашем следующем примере выражение это вычисление.

Результат — Hello Angular 42 .

Angular выполнил выражение и показал результат.

Запомните, это работает в браузере, так что если вы нажмете «view source», то увидите этот код как и обычный html файл.

Переменные в выражениях AngularJS

В следующем все еще очень простом примере, мы сможем увидеть, как можно присваивать значения переменным, а затем мы сможем использовать эти переменные в выражениях.

Замечание: здесь мы не используем var для присвоения значений переменным, потому что это на самом деле атрибуты внутреннего объекта AngularJS.

Разделим установку переменной и ее использование на два выражения.

Мы можем даже присвоить значение переменной в одном выражении, а использовать ее в другом. И не только. Даже расположение этих выражений в HTML не имеет значения. Как мы можем выдеть в следующем примере, мы можем использовать переменную даже до ее установки:

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

Для решения проблемы можно добавить другой оператор к выражению присваивания, который не будет возвращать видимого значения. Это может быть null или » (пустая строка).

Шпаргалка по AngularJS

Эта статья позволит быстро освоить основы JavaScript-фреймворка AngularJS.

Другие статьи по AngularJS:

С чего начать

    1. Подключаем скрипты фреймворка на страничку (взять можно здесь), как минимум, Вам потребуются: angular.js, angular-route.js, angular-locale_ru-ru.js. В рассматриваемом здесь приложении мы используем анимацию, поэтому добавим еще и angular-animate.js.
    2. Создаем app.js — это будет «точка входа» в приложение angular. Внутри объявляем корневой модуль приложения и его зависимости, конфигурируем роуты; если нужно, определяем функцию, которая выполнится при старте приложения, и оборачиваем все это в вызов анонимной функции, «чтобы наружу не торчало ничего»:

    Рассмотрим код подробнее.
    Конструктор модуля принимает два аргумента — имя модуля и массив имен модулей, от которых он зависит.
    Функция config выполняется в момент старта приложения, здесь, во-первых, задается роутинг, а во-вторых, конфигурируются сервисы, предоставляемые провайдерами… ок, мы еще вернемся к этому.
    При конфигурации маршрутов мы задаем url шаблона, который нужно использовать для рендеринга (также можно прямо на месте строкой передать inline-шаблон, только не в templateUrl , а template , но лучше так не делать вообще никогда). Часто здесь же параметром controller обычно задается контроллер (сюрприз!), который будет использоваться для взаимодействия с шаблоном, но мы этого делать не будем, позже объясню почему.
    Функция run выполняется после загрузки всех модулей, нам нечего делать на этом этапе, поэтому мы ничего не делаем в ней (то есть ее можно было вообще не передавать в .run()). Но, к примеру, здесь можно получить текущего пользователя из сессии и сохранить его $rootScope.
    А что за $rootScope ? Для начала стоить сказать, что такое $scope . Скоуп — это модель, «клей» между логикой и шаблонами. Скоупы компонуются и наследуются, образуя древовидную структуру, в контексте скоупов выполняются выражения в шаблонах, скоуп может следить ( $watch ) за выражениями (а также функциями, коллекциями, переменными) и бросать события. Все, что есть в скоупе — доступно в связанном с ним шаблоне и в его дочерних скоупах. На самом деле, я сейчас просто пересказал вступление к статье по скоупам из официальной документации, поэтому советую все же заглянуть в первоисточник.
    Теперь, когда мы разобрались (разобрались же?), что такое скоуп, можно пояснить, что такое $rootScope — это, как не трудно догадаться, родительский скоуп всех скоупов в приложении. Ключевые моменты:

    • Одна штука на приложение
    • Доступен из любого места приложения, достаточно внедрить $rootScope
    • Ловит все события
    • Соответственно, события, брошенные им, дойдут до любого дочернего скоупа
    • Превращается в помойку при злоупотреблении
  1. На страничке приложения в тэг html или body добавляем директиву ng-app=»dummy» тем самым заявляя, что внутри этого тэга будет работать angular-приложение dummy, точка входа в которое описана в одноименном модуле.
  2. Где-то внутри body добавляем блок с директивой ng-view — здесь будут рендериться наши шаблоны в соотстветствии с текущим роутом.
Цукерберг рекомендует:  Как справляться с усталостью от программирования

Это основные приготовления для angular-приложения. Теперь, прежде чем начать штамповать контроллеры и сервисы, замолвим слово про структуру приложения.


Структура приложения

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

Корневая директория называется по имени самого приложения, в ней лежат: контроллер верхнего уровня (app-controller.js), базовые стили приложения (app.css), дефолтный шаблон (app.html) и главный модуль приложения (app.js).

  • разделы приложения (foo и bar), каждый со своими контроллером, шаблоном и стилями;
  • компоненты: здесь храним директивы, сервисы и т.д., которые разделяются по функционалу/сущностям, к которым они относятся (например, все, что имеет дело с message, лежит в одной директории), каждая директива лежит отдельно от другой;
  • конфигурация — здесь, соответственно все constant и value сервисы (url-config.js) и модуль (config.js), в котором все это содержится.

Предлагаемая структура — иерархическая, например, если раздел foo у нас сильно усложнится и мы решим разбить его на части, то файлы дочерних разделов уже будут храниться в поддиректориях foofoo/customer«, «foo/supplier«).

Структура модулей соответствует файловой, то есть сервисы MessageManagerFactory и MessageService содержатся в модуле dummy.message , директива MessageList — в модуле dummy.message.messageList , директива MessagePoster — в модуле dummy.message.messagePoster (да, каждая директива хранится в собственном модуле).

Контроллер

Контроллер — это функция-конструктор, которая используется для «оживления» шаблона. Типичный сценарий использования: шаблон привязывают к контроллеру на этапе конфигурации, в контроллер передают $scope , набивают его под завязку всеми данными и логикой, которые используются на странице, а потом пытаются совладать с 600-строчным чудовищем. Так делать не надо.
Во-первых, $scope нужно использовать только тогда, когда без него не обойтись вообще никак, то есть вызов $watch , $emit , $broadcast и т.д. Все функции, объекты и поля лучше держать в экземпляре контроллера:

В данном случае, в конструкторе мы инициализируем поле saidHi , создаем экземпляр MessageManager , в котором инкапсулируем работу с сообщениями, а также создаем пустой массив для хранения сообщений. Функции, которые будем использовать в шаблоне, выносим в прототип.

Убирая код, работающий с сообщениями в MessageManager , мы не только уменьшаем количество кода в контроллере (что само по себе хорошо), но и избавляемся от зависимостей, которые этот код может за собой тащить. (Да, конкретно для данного случая — это overkill, MessageManager всего-то умеет дергать сервис для отправки/получения/удаления сообщений и выполняет простые callback’и, но идея, думаю, ясна).

$scope же здесь используется только для задания обработчика события message.new.local (мы ждем, что один из дочерних контроллеров или директив может создать новое сообщение).

В шаблоне все это используется так:

AppController объявлен как «главный» контроллер приложения, поэтому он будет доступен везде как appCtrl . Это удобно, но так же, как и с $rootScope этим лучше не злоупотреблять. В данном приложении мы используем эту возможность для доступа к списку сообщений в дочерних контроллерах.

Использование в шаблоне членов экземпляра контроллера, а не скоупа, защищает нас от трудноуловимых багов — мы всегда точно знаем, что именно будет использоваться. Кроме того, двухсторонний биндинг примитивов в дочерних скоупах будет работать корректно без дополнительных оберток.

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

В самом шаблоне, все достаточно просто: показываем «приветствие» из поля greeting , которое меняется по клику на кнопку «Say Hi». Далее у нас подключена директива messageList для вывода списка сообщений. Для запросов к серверу для получения, отправки и удаления сообщений служат три кнопки «Save new», «Get all», «Delete all», а статус выполнения запроса выводится чуть ниже.

Директивы

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

Директивы можно разделить на два типа: изменяющие поведение элемента (draggable, collapsable и т.д.) и кастомные ui-компоненты (контрол для пагинации, календарь, модальное окно).

Директива должна делать одну и только одну вещь, не нужно собирать мега-комбайны, делающие все на свете.

Рассмотрим код простой директивы, оборачивающей элемент в «гармошку» — collapsable:

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

Для данной директивы нам потребовалось задать всего четыре параметра:

1) restrict — определяет, в качестве чего можно использовать директиву, возможные варианты: A — атрибут, E — элемент, и, с недавних пор, С — класс.

2) link — основная функция для «поведенческих» директив, здесь мы имеем доступ к $scope , jqueryLite-обертке элемента, к которому директива применена, и его атрибутам (в виде хэша). link выполняется после того, как манипуляция с DOM (для этой директивы) была завершена.

3) transclude — с этим все не так просто. Если установлен в true , изменяет скоуп директивы так, что его содержимое замещается содержимым родительского скоупа. Таким образом, если и в скоупе директивы, и в скоупе контроллера задать одноименные поля, в шаблоне директивы использоваться будет поле из скоупа контроллера. Этот параметр следует использовать только вместе c директивой ng-transclude , для подстановки фрагмента DOM извне в «тело» директивы — вставленный фрагмент шаблона не потеряет доступ к переменным в родительском $scope, если он их использовал, и нам не придется передавать их в качестве параметра (ну и если не выставить trancslude в true , у вас вылетит Error: orphane ng-transclude directive ). В данном случае, список сообщений (message-list) будет «подставлен» внутрь блока div в шаблоне директивы с атрибутом ng-transclude (при этом все текущее содержимое div’a будет удалено).

4) templateUrl — url, по которому будет запрошен шаблон для директивы.

Теперь рассмотрим директиву с изолированным скоупом — messageList :

Здесь в конфиге директивы три новых параметра:

  1. scope — если сюда передать хэш (даже пустой), у директивы будет изолированный скоуп (неизолированный скоуп прототипически наследует родительский). Заполняется этот хэш таким образом, что ключ — это название свойства у скоупа, а значение — имя атрибута, значение которого будет связано с этим свойством. На то, как именно будут «забиндены» значения атрибутов на свойства в скоупе, влияют префиксы перед именем атрибута:
    • @ — значение из атрибута будет передано в свойство скоупа директивы строкой.
    • & — свойство директивы будет функцией, интепретирующей выражение, содержащееся в атрибуте. Именно этот префикс используется здесь. Таким образом, вызов $scope.getMessages() вызовет appCtrl.getMessages() и вернет массив сообщений.
    • = — свойство скоупа директивы будет «забиндено» на объект, имя которого указано в атрибуте, т.е. будет создана двухсторонняя связь.
    • ? — флаг необязательности наличия значения, используется в дополнение к другим.
  2. controller — имя контроллера, который будет прикреплен к шаблону директивы.
  3. replace — если установлен в true, блок директивы будет заменен контентом шаблона директивы.

В контроллере директивы можно также увидеть использование функции $watchCollection — angular будет следить за состоянием массива или хэша, если его состояние изменится, будет вызвана callback функция с двумя параметрами — newValue и oldValue .

В шаблоне мы выводим список сообщений в messages с помощью ng-repeat , при этом выполняется сортировка по полю, имя которого хранится в sortBy , sortBy при этом задается из select’a.

Для каждого сообщения мы выводим дату, при этом форматирование выполняется с помощью фильтра angular’a date .

Сервисы

Видов сервисов в angular — пять штук:

Неизменяемый объект или примитив. Может быть использован на этапе конфигурации.

  • value — изменяемый объект или примитив. Не может быть использован на этапе конфигурации.
  • factory — сервис, возвращающий какой-либо объект (неважно какой). Приведем фрагмент фабрики MessageManagerFactory :

    В фабрике определена функция-конструктор объектов MessageManager , заданы методы прототипа MessageManager , приватные функции вынесены в хэш _private , и объявлена «статическая» приватная функция _filterNew (статическая в том смысле, что не обращается к членам экземпляра MessageManager ). На выходе фабрики — литерал объекта с единственным методом — make .
    service — отличается от фабрики тем, что при первом использовании функция будет использована как конструктор объекта. Приведем код нашего сервиса сообщений:

    В сервисе определяется конструктор объектов Message (возможно, не самое лучшее решение, да); url для вызова api сервера берется из constant сервиса urlConfig ; для экземпляра самого сервиса определены методы для вызова сервера ( post , delete , get ), метод для создания экземпляра Message и метод для конвертации из json, пришедшего с сервера, в объект Message (все сообщения с сервера конвертируются, таким образом, все наши сообщения в angular-приложении — экземпляры Message ).
    provider — сервис, который можно использовать, если требуется некая конфигурация при старте приложения. В таком сервисе должна быть определена функция $get() , результат выполнения которой будет предоставлен клиенту сервиса. В сам провайдер можно добавить какие-либо функции для его конфигурации:

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

    Подробнее о наследовании $scope


    Скоупы в большинстве случаев ( ng-include , ng-switch , ng-controller , ng-transcluded , директивы с параметром scope: true ) наследуются прототипически (не уверен, что есть такое слово), из чего следует:

    • Изменение примитива в дочернем скоупе создает новое поле в нем, не оказывая эффекта на этот примитив в родительском скоупе.
    • Изменение поля в объекте в дочернем скоупе изменяет это поле в соответствующем объекте в родительском скоупе.
    • Изменение ссылки на объект в дочернем скоупе создает новую ссылку в нем, ссылка в родительском скоупе не изменяется.

    Стоит отметить, что ng-repeat создает новый скоуп для каждой итерации, значения полей которого копируются из соответствующего элемента итерируемой коллекции родительского скоупа. Поэтому не стоит использовать массивы примитивов в ng-repeat , разве что только для read-only.

    Скоупы не наследуются прототипически в следующих случаях:

    1. Создание директивы с параметром scope: false (по умолчанию). В данном случае, директива использует родительский скоуп как свой собственный, что естественно нежелательно использовать, т.к. может привести к трудноуловимым багам.
    2. Создание директивы с параметром scope: <> . Как уже говорилось выше, создает изолированный скоуп. Поля такого скоупа никак не связаны с родительскими, однако доступ к его полям (родителя) можно получить через атрибуты-параметры директивы (используя биндинги ‘@’, ‘&’ и ‘=’).

    Доступ к родительскому, соседнему или дочерним скоупам можно получить с помощью следующих свойств: $scope : $parent , $$nextSibling , $$childTail и $$childHead .

    Подробнее обо всей этой кухне можно почитать здесь.

    О применении $scope.$apply()

    Вызов этой функции заставляет angular обновить состояние шаблона в соответствии c актуальным состоянием шаблона, однако, если вам пришлось использовать это — скорее всего, вы сделали что-то неправильно: использовали setTimeout вместо $timeout , setInterval вместо $interval , element.on(‘click’) вместо ng-click и т.д. В редких случаях использование $apply оправдано — необходимо изменить модель извне angular -приложения, но мне пока не приходилось с таким сталкиваться. В таких случаях использовать $apply нужно следующим образом (украдено отсюда):

    И далее вызываем safeApply() везде, где нам требуется вызов $apply() .

    Ссылка на репозиторий демо-приложения на гитхабе: ng-help.

    Блог Makeomatic: разработка сайтов и мобильных приложений

    Angular.JS: введение и основные концепции

    разбираем Angular.JS на пальцах

    Подготовка

    Различия версий

    На момент написания (начало июля 2013) готовится к выходу AngularJS 2.0, который будет фактически представлять собой 1.1.5 с минимальными изменениями.

    Отличия между 1.1.5 и 1.0.7 уже достаточно велики, и рассматривать технически устаревшую 1.0.7 нет смысла.

    Установка

    Google рекомендует использовать версию AngularJS, поставляемую через CDN, для рабочих окружений. Для разработки следует скачать архив, включающий в себя полноценные отладочные версии библиотеки, поскольку только они предлагают досточно подробные сообщения об ошибках. Впрочем, в 2.0 планируется серьёзно улучшить этот вопрос, так как сейчас сообщения об ошибках практически не дают понимания происходящего.

    Подключение

    Следует сразу отметить, что AngularJS проповедует декларативный подход, поэтому ваше приложение вообще может не включать ни единой строчки JavaScript и вполне нормально работать.

    Для подключения AngularJS к веб-странице достаточно подключить основной файл:

    В примере выше используются сразу две основных концепции AngularJS: область видимости и двойное связывание данных. Рассмотрим их подробнее ниже.

    Основные концепции

    Область видимости

    Область видимости (scope) является наиважнейшим элементом AngularJS и ведёт себя идентично области видимости переменных в классических языках программирования. Так же, как и, к примеру, в C, существует глобальная область видимости и существуют вложенные в неё дочерние. Однако, в отличие от C, области видимости в AngularJS играют намного более важную роль.

    Цукерберг рекомендует:  Обучение - Техника профессионалов

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

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

    В-третьих, AngularJS не работает за пределами какой-либо области видимости.

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

    Применение к области видимости

    Важно: если вы изменяете какой-либо объект, лежащий внутри области видимости, из-за пределов AngularJS, необходимо всегда вызывать метод $scope.$apply. Мы вернёмся к этому чуть позже.

    Связывание данных

    AngularJS предлагает концепцию связывания данных (data binding), работающую в обе стороны. Однако следует обратить внимание на то, что центровым объектом связывания данных всегда является область видимости. Только объекты, находящиеся внутри области видимости, могут участвовать в связывании данных.

    Как это работает

    Обратимся к примеру выше. В нём имеется поле ввода, к которому привязана переменная, лежащая внутри области видимости, автоматически созданной AngularJS (это не глобальная область видимости). ngModel является директивой, которая меняет поведение того или иного элемента DOM. В данном случае, эта директива связывает содержимое input и переменную в области видимости. Это не магия, это не более чем директива, которую вы легко можете реализовать самостоятельно, однако разработчики уже реализовали её, потому что такое поведение требуется очень часто.

    Чисто технически, директива добавляет обработчик события изменения введённого в input значения, в котором производит вызов $scope.$apply для изменения переменной в области видимости, а также применяет обработчик $scope.$watch на области видимости, в котором меняется значение в поле ввода.

    Попробуйте ввести в поле ввода любой текст и понаблюдать, как изменяется выводимый текст. Попробуйте открыть консоль и ввести $scope.yourName = «test» , обратите внимание, что текст и значение в поле ввода не изменились, так как AngularJS ничего не знает про консоль и не может отследить изменения, произведённые из неё. Теперь введите $scope.$apply() и изменения обработаются AngularJS.

    Важно: любые события браузера вызываются вне области видимости AngularJS, поэтому внутри ваших обработчиков таких событий необходимо вызывать $scope.$apply.

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

    Внедрение зависимостей (dependency injection, DI) является третьим краеугольным камнем AngularJS, однако он не относится непосредственно к логике работы библиотеки, а скорее к организации кода.

    Грубо говоря, DI позволяет любой функции сказать: «мне нужны эти сервисы, эти и эти», после чего AngularJS автоматически предоставит эти сервисы, где бы они ни были реализованы и где бы ни находились. Разумеется, это работает только в пределах AngularJS.

    Сервис

    Сервис в DI — не более, чем некоторый объект, который предоставляет некоторую функциональность. Это может быть что угодно, от простой константы до фабрики классов.

    Приложение


    Теперь можно поговорить о том, как описанные выше концепции работают вместе для реализации приложений.

    Каркас и ng-app

    Вся библиотека AngularJS разбита на независимые модули, соответственно от вашего приложения ожидается такая же организация и для этого предоставлено всё необходимое.

    ngApp это директива, сообщающая AngularJS: «здесь находится приложение». DOM, окружённый элементом с этой директивой будет работать под управлением AngularJS.

    Создание модуля

    Для начала сообщим AngularJS, что мы хотим не просто создать приложение, а подключить к нему собственную функциональность:

    Само приложение является просто модулем, давайте создадим его (важно: имя модуля должно совпадать со значением, переданным директиве ngApp):

    var app = angular.module(«tutorial», [])

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

    Общая форма внедрения зависимостей выглядит так:

    [«dependency1», «dependency2», . function(dependency1, dependency2, . ) <>]

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

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

    В данном случае наоборот, важны имена параметров, а не их порядок. В первом случае мы передаём имена в виде строк, которые не будут изменены при сжатии кода, во втором случае имена извлекаются из параметров функции, поэтому изменение имени параметра будет иметь плачевные последствия.

    Настройка провайдеров

    Провайдер — это функция, которая отвечает за создание сервисов. Если требуется перед внедрением сервиса в функцию настроить его функциональность, следует обращаться к провайдеру. Наличие/отсутствие провайдера у сервиса определяется целиком и полностью его разработчиком.

    В примере выше мы настроили работу сервиса $location, включив режим html5. Теперь приложение будет работать с полноценными URL, без использования хэшей, если браузер поддерживает HTML5 History API.

    Аналогичным образом настраиваются другие сервисы.

    MVC в AngularJS реализовано отдельным модулем и не играет важной роли в самой библиотеке. Вы можете пользоваться любой сторонней реализацией, или разработать собственную.

    Для включения MVC в 1.1.5 не требуется дополнительных действий. В 1.1.6 (и 2.0) потребуется подключить angular-router.js и в зависимости приложения добавить ngRoute:

    ngRoute настраивается с помощью $routeProvider, например, так:

    Подробнее о том, что здесь происходит, вы можете прочитать в документации к модулю ngRoute или в справке по $route на сайте AngularJS.

    Модели

    Как таковых, моделей в AngularJS нет. Использованная выше ngModel — не более чем директива, меняющая поведение DOM, а model лишь удобное имя. Вы можете использовать к примеру модели Backbone.js, а можете вообще запрашивать данные с сервера вручную или пользоваться модулем ngResource (читайте документацию $http и $resource).

    Важно помнить, что всё связывание данных происходит исключительно на области видимости. Поместили модель в область видимости? Всё отлично работает.

    Контроллеры

    В отличие от моделей, концепция контроллеров в AngularJS есть, однако относятся контроллеры здесь непосредственно к DOM. Рассмотрим пример:

    И код контроллера (заодно узнаем, как они создаются):

    В контроллер необходимо внедрить хотя бы $scope, в противном случае он будет вещью в себе и не сможет ничего сделать с областью видимости, а именно для этого предназначен контроллер. Однако в 2.0 предлагается новый, упрощённый вариант создания контроллеров:

    Обратите внимание, способы не равнозначны. И this.yourName не будет равен $scope.yourName . Однако второй способ позволяет вообще не внедрять $scope в контроллер и очистить код от ненужных зависимостей. Кроме того функции контроллера не будут зависеть от $scope и их можно будет использовать в других частях приложения, а не только в одной конкретной области видимости (по этой же причине рекомендуется передавать в функции контроллера параметры, а не полагаться на $scope).

    Важно: контроллер всегда создаёт внутреннюю область видимости, поэтому в примере ниже anotherName видно лишь внутри anotherCtrl, и мы всегда будем видеть «Не привет,», какой бы текст во второе поле ввода мы ни вводили. Проверьте, что будет выведено внутри anotherCtrl для yourName. Почему?

    Внутри anotherCtrl существует своя область видимости, однако родительская по отношению к нему область видимости также доступна из него. В данном случае < < yourName >> правильнее было бы записать как < < $parent.yourName >> . При этом выражение с yourName будет верно вычислено в обоих случаях и мы увидим «Ещё раз привет, Вася», если ввести «Вася» в поле ввода, относящееся к контроллеру defaultCtrl .

    У каждой области видимости есть свойства $parent (указывает на родительскую область видимости) и $root (указывает на глобальную область видимости).

    Важно: контроллер должен существовать, иначе AngularJS выдаст ошибку.

    Не рекомендуемый способ создавать контроллеры:

    В данном случае вы не только засоряете глобальную область видимости JS (не область видимости AngularJS), но ещё и лишаетесь возможности грамотно организовать DI.

    ngView

    Директива ngView позволяет динамически подгружать часть HTML в зависимости от значения templateUrl в настройках $routeProvider. Это делается $route автоматически, равно как и подключение указанного контроллера.

    Важно: стандартная реализация поддерживает лишь один ngView на приложение. Вложенные ngView также не поддерживаются.

    Для расширенных возможностей MVC рекомендуется использовать AngularUI-Router, поддерживающий вышеописанный функционал.

    Шаблоны и выражения

    Здесь мы поговорим о V из MVC применительно к AngularJS. Раздел вынесен отдельно ввиду большой важности.

    Выражения

    Выражением в AngularJS считается практически любое выражение JavaScript. Вы можете выполнять математические операции, вызывать функции и т.д. Существуют ограничения, с которыми вы можете ознакомиться в документации, мы же рассмотрим для чего используются выражения.

    Выражение в AngularJS заключается в двойные фигурные скобки и может быть использовано непосредственно в DOM. AngularJS вычисляет выражение и подставляет его значение прямо в DOM. При этом используются все преимущества связывания данных: значение выражения обновляется с изменением входящих в него переменных (или результатов вычисления функции).

    Здесь я использовал не рекомендованный стиль кода с привязкой к $scope внутри обработчика, поскольку это нагляднее показывает, что связывание данных в AngularJS работает даже в том случае, если выражение не содержит прямой ссылки на данные.

    Шаблоны


    Шаблоны в AngularJS это не более, чем обычный HTML, расширенный с помощью директив и выражений. Выражения используются для вывода данных, директивы — для расширения функциональности HTML, превращая его в DSL (Domain Specific Language) для вашего конкретного приложения. Вы можете добавить директиву, создающую интерфейс с вкладками, можете добавить директиву, которая выводит в цикле содержимое массива с данными (такая директива встроена в AngularJS), можете выводить HTML в зависимости от значения той или иной переменной и так далее. Всё ограничено лишь вашей фантазией. Подлинная мощь AngularJS заключена именно в директивах, а обычный

    Создание директив — расширенная тема, к которой мы обратимся позже, равно как и к созданию сервисов.

    Angular,основы Как это работает?

    Читаю книгу «Angular для профессионалов», только начал осваивать. И не могу понять, как это работает. Есть вот такой код:

    В конструкторе указан параметр,в котором говорится, что на вход конструктору должен прийти экземпляр типа StaticDatasource. У которого есть метод getProducts(). Его код в данной ситуации не особо важен. Меня интересует, каким образом туда попадают данные, ведь нет никакой явной инициализации переменной типа StaticDatasource. Откуда он её берёт? Ведь аннотация в конструкторе просто указывает, что в конструктор должен быть передан объект такого-то типа, или я что-то не правильно понял? Поясните, пожалуйста.

    Как работает привязка данных в AngularJS?

    Как привязка данных работает в рамках AngularJS ?

    Я не нашел технических подробностей их сайта. Это более или менее понятно, как это работает, когда данные распространяются из представления в модель. Но как AngularJS отслеживает изменения свойств модели без сеттеров и геттеров?

    Я обнаружил, что есть наблюдатели JavaScript, которые могут выполнять эту работу. Но они не поддерживаются в Internet Explorer 6 и Internet Explorer 7. Итак, как AngularJS знает, что я изменил, например, следующее и отразил это изменение в представлении?

    AngularJS запоминает значение и сравнивает его с предыдущим значением. Это основная грязная проверка. Если есть изменение в значении, то он запускает событие изменения.

    Метод $apply() , который вы называете, когда вы переходите из мира без углов в мир AngularJS, вызывает $digest() . Дайджест — просто обычная грязная проверка. Он работает во всех браузерах и полностью предсказуем.

    Чтобы контрастировать с грязной проверкой (AngularJS) и сменить слушателей (KnockoutJS и Backbone.js): Хотя проверка грязности может показаться простой и даже неэффективной (я расскажу об этом позже), выясняется, что она семантически корректна все время, в то время как у слушателей изменений есть много странных угловых случаев и нужны такие вещи, как отслеживание зависимостей, чтобы сделать это более семантически правильно. Отслеживание зависимостей KnockoutJS — это умная функция для проблемы, которую не имеет AngularJS.

    Проблемы с прослушивателями изменений:

    • Синтаксис является жестоким, поскольку браузеры не поддерживают его изначально. Да, есть прокси, но они не являются семантически правильными во всех случаях, и, конечно, в старых браузерах нет прокси-серверов. Суть в том, что грязная проверка позволяет вам выполнять POJO, тогда как KnockoutJS и Backbone.js заставляют вас наследовать их классы и получать доступ к вашим данным через аксессуры.
    • Изменение коалесценции. Предположим, у вас есть массив элементов. Предположите, что вы хотите добавлять элементы в массив, поскольку вы добавляете цикл, каждый раз, когда вы добавляете, вы запускаете события с изменениями, которые отображают пользовательский интерфейс. Это очень плохо для производительности. Вы хотите обновить интерфейс только один раз, в конце. События изменения слишком мелкие.
    • Смена слушателей немедленно срабатывает на сеттере, что является проблемой, поскольку прослушиватель изменений может дополнительно изменять данные, что вызывает больше изменений событий. Это плохо, так как в вашем стеке у вас может быть несколько изменений, происходящих сразу. Предположим, у вас есть два массива, которые нужно синхронизировать по любой причине. Вы можете добавлять только одно или другое, но каждый раз, когда вы добавляете, вы запускаете событие изменения, которое теперь имеет непоследовательное представление о мире. Это очень похожая проблема для блокировки потоков, которую JavaScript избегает, поскольку каждый обратный вызов выполняется исключительно и завершается. Изменение событий нарушает это, поскольку сеттеры могут иметь далеко идущие последствия, которые не предназначены и не очевидны, что снова создает проблему потока. Оказывается, что вы хотите отложить выполнение слушателя и гарантировать, что только один прослушиватель работает одновременно, поэтому любой код может свободно изменять данные, и он знает, что никакой другой код не работает, пока он делает это.

    Как насчет производительности?

    Таким образом, может показаться, что мы медленны, поскольку грязная проверка неэффективна. Здесь нам нужно посмотреть реальные числа, а не просто теоретические аргументы, но сначала определим некоторые ограничения.

    Slow — все, что быстрее, чем 50 ms, незаметно для людей и поэтому может считаться «мгновенным».

    Цукерберг рекомендует:  Плавная замена одного изображения другим с использованием спрайта CSS

    Limited. Вы не можете показать более чем 2000 единиц информации человеку на одной странице. Что-то большее, чем это действительно плохой пользовательский интерфейс, и люди все равно не могут его обработать.

    Итак, реальный вопрос заключается в следующем: сколько сравнений вы можете сделать в браузере в 50 ms? Это сложный вопрос для ответа, поскольку многие факторы вступают в игру, но вот тестовый пример: http://jsperf.com/angularjs-digest/6, который создает 10 000 наблюдателей. В современном браузере это занимает всего 6 мкс. В Internet Explorer 8 требуется около 40 мкс. Как вы можете видеть, в наши дни это не проблема даже в медленных браузерах. Существует предостережение: сравнения должны быть простыми в соответствии с временными ограничениями. К сожалению, слишком легко добавить медленное сравнение в AngularJS, поэтому легко создавать медленные приложения, когда вы не знаете, что вы делаем. Но мы надеемся получить ответ, предоставив модуль приборов, который покажет вам, которые являются медленными сравнениями.

    Оказывается, видеоигры и графические процессоры используют подход с грязной проверкой, особенно потому, что он согласован. Пока они превышают частоту обновления монитора (обычно 50-60 Гц или каждые 16,6-20 мс), любая производительность по сравнению с этим является пустой тратой, поэтому вам лучше рисовать больше, чем получать FPS выше.

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

    Как заявила Мишко, около 2000 привязок — это то, где вы начинаете видеть проблемы, но в любом случае вы не должны иметь более 2000 единиц информации на странице. Это может быть правдой, но не все данные привязываются к пользователю. После того, как вы начнете создавать какой-либо виджет или сетку данных с двусторонней привязкой, вы можете легко ударить 2000 привязок, не имея плохих ux.

    Рассмотрим, например, combobox, где вы можете набирать текст для фильтрации доступных параметров. Такой контроль может иметь

    150 элементов и по-прежнему может быть очень полезен. Если у него есть дополнительная функция (например, определенный класс в выбранном в данный момент параметре), вы получаете 3-5 привязок для каждого параметра. Поместите три из этих виджетов на страницу (например, один, чтобы выбрать страну, а другой выбрать город в указанной стране, а третий — выбрать отель), и вы уже где-то между 1000 и 2000 привязками.

    Или рассмотрите сетку данных в корпоративном веб-приложении. 50 строк на страницу не являются необоснованными, каждая из которых может содержать 10-20 столбцов. Если вы построите это с помощью ng-повторов и/или получите информацию в некоторых ячейках, которые используют некоторые привязки, вы можете приблизиться к 2000 привязкам только с этой сеткой.

    Я считаю, что это проблема огромная при работе с AngularJS, и единственным решением, которое я смог найти до сих пор, является создание виджетов без использования двусторонней привязки, вместо этого используя ngOnce, отмену регистрации наблюдателей и т.д., или создавать директивы, которые строят DOM с манипуляциями jQuery и DOM. Я чувствую, что это побеждает цель использования Angular в первую очередь.

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

    TL; DR
    Связывание данных может вызвать проблемы с производительностью на сложных страницах.

    Stepan Suvorov Blog

    Release 2.0

    Самые распространенные ошибки AngularJS разработчиков

    Пост представляет собой микс перевода/переработки статьи The Top 10 Mistakes AngularJS Developers Make и личного грабельного опыта.

    Введение

    Думаю многие согласятся, что AngularJS один из самых популярных JavaScript фреймворков на сегодняшний день. Что делает его таким популярным? Наверное то, что он серьезно упрощает процесс разработки прототипов, и также позволяет расширять эти прототипы до полноценных многофункциональных приложений. Широкое распространение фрейворка привело в свою очередь к широкому распространению ошибок связанных с ним. Ниже приведен список самых часто встречаемых ошибок.

    1. “MVC” структура директорий проекта

    AngularJS – грубо говоря MVC фреймворк: модели не так четко выделены как в Backbone, но архитектурный паттерн все же похож. Когда мы работаем в рамках MVC фремфорка, общая практика – группировать файлы основываясь на их типе, то есть:

    Это выглядит как очевидный лэйаут, особенно если вы пришли откуда-то из Rails. Однако, как только приложение начинает расти, такое расположение приводит к тому, что много папок открыто одновременно. Чтобы бы вы не использовали Sublime, Visual Studio или Web Storm, много времени уходит на прокручивание дерева ресурсов. Вместо этого можно группировать файлы основываясь на фиче/модуле/предназначении:

    Такая структура директорий делает поиск конкретного файла намного проще и соотвественно ускоряет разработку. В итоге для нашего проекта мы пришли к вот такоймодульной структуре.

    2. Модули (а точнее – их нехватка)

    Обычно, когда вы начинаете делать прототип, вы все складываете в главный модуль, иногда даже просто в один файл, и это работает:

    В процессе разрастания приложения вы стараетесь уже группировать сущности с использованием модулей:

    Как вы уже наверное обратили внимание: ошибка полностью аналогична ошибке с директориями. И правильным решением будет группировка по функциональному предназначению:

    и конечно, в большом приложении все это должно быть разнесено по отдельным файлам.

    3. Внедрение зависимостей (Dependency injection)


    Dependency injection – один из лучших паттернов AngularJs. Он делает тестирование намного проще, на ряду с тем, что все зависимости становятся более понятно описаны. AngularJS очень гибок в плане того, как могут быть внедрены зависимоcти. Самый легкий способ: просто передать имя зависимости в функцию как параметр:

    – вполне понятно, что MainCtrl зависит от $scope и $timeout. Это прекрасно работает до момента, когда вы захотите минифицировать код. Он может превратиться в что-то такое:

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

    в данном случае после компиляции получим:

    Так же эту проблему можно решить с помощью ngAnnotate модуля, который сам переведет ваш код в полную форму записи перед минификацией.

    3.1 Глобальные зависимости

    Часто при разработке на AngularJS возникает необходимость использования сторонних библиотек, которые в большей части представляют из себя глобальные объекты/функции (то есть доступны в любом месте кода). То, что мы можем их везде использовать не задумываясь о подключении, – это хорошо, но ломает паттерн ангуляра и ведет к ряду неприятных последствий при тестировании(и не только). AngularJS позволяет легко завернуть эти глобальные переменные в модули/сервисы и потом их подключать.

    Например библиотека Underscore.js, которая существенно упрощает JavaScript код, может быть обернута в модуль/сервис следующим образом:

    Это позволит сохранить структуру зависимостей AngularJS, и в дальнейшем мы сможем выгрузить(либо перегрузить) Underscore.js для тестов.

    Может показаться, что это лишняя и ненужная работа, но если вы следуете “use strict” для всего вашего кода – данные изменения будут необходимы.

    4. Толстые котроллеры

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

    Данные также должны храниться в сервисах (за исключением тех случаев, когда это временные данных представления завязанные на $scope). Сервисы являются синглтонами и сохраняют свое значение на протяжении всей работы с приложением, а вот контроллеры могут перегружаться при изменении состояния. Если данные сохранены в контроллере, тогда они будут загружаться каждый раз при перезагрузке контроллера. Даже, если данные сохранены локально (например в localStorage), намного быстрее получить данные из JavaScript переменной.

    5. service или factory

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

    Так чем же все таки они отличаются? Суть скрывается в методе $injector.instantiate, благодаря которому инжектор создает новую сущность сервиса используя его функцию-конструктор.

    Вот пример использования service и factory, которые делают одно и тоже:

    При внедрении сущностей в обоих случаях мы получим в контроллере сущность, которая будет содержать метод hello(). Функция-конструктор для сервиса будет инициализирована один раз при объявлении, в том время как объект фабрики создается каждый раз при инжекте. Да, конечно, мы можем реализовать service так, что он будет вести себя как factory.

    Так зачем нужны 2 способа? factory предполагает более гибкую настройку, чем service, потому что она может вернуть функцию-конструктор, которая будет использована для создания объекта (из этого паттерна вероятно и происходит название сущности).

    Вот пример использования такой фабрики в контроллере:

    Другими словами: когда начинаете разрабатывать приложения на основе AngularJS и вам не нужен паттерн “фабрика”, то просто используйте service .

    Фабрика может пригодиться там, где у нас много приватных методов:

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

    6. Игнорирование инструментов Batarang и ng-inspector

    Batarang – расширение для Chrome браузера. Более подробно в этом посте.

    • просмотр модели scope (может быть полезно при работе с изолированным scope)
    • граф зависимостей (например: для выявления перегруженных сущностей)
    • аналитика производительности (для определения наиболее ресурсоемких операций)

    ng-inspector – еще одно полезное расширение для Chrome (так же существует для Safari). Предоставляет удобный обзор структуры scope (что в Batarang сделано не самым лучшим образом).

    7. Слишком много вотчеров

    Как было отмечено в предыдущем пункте: AngularJS довольно производительный уже “из коробки”. Но когда число вотчеров превысит 2000, это может стать реальной проблемой. (Это собираются пофиксить в AngularJS 1.3, более подробно можно почитать тут)

    Вот этот код покажет количество вотчеров на странице(можно быстро проверить в консоли):

    Старайтесь выявлять места, где можно обойтись без дополнительных вотчеров. Помочь в этом может Batarang. Для тех случаев, когда нам не нужно двойное связывание, а необходимо просто вывести информацию в темплейт, можно использовать вспомогательный модуль bindonce, который предоставляет специальные директивы – аналог ангуляровским, только без вотчеров.

    8. Путаница с наследованием $scope

    Есть некоторые нюансы прототипного наследования (используемого в javascript), которые проявляются при работе со $scope, так как каждый $scope наследуется от родительского $scope и так далее до самого верхнего уровня $rootScope.

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

    !Внимание вопрос: какие поля шаблона обновятся (когда юзер вводит текст)?

    Если вы сразу же ответили “только loginCtrl“, вероятно вы уже понимаете логику наследования. Поиграться с примером можно тут.

    Суть в том, что примитивы передаются как значение , а объекты по ссылке . Поэтому, если мы хотим, чтобы обновилось также значение в котроллере navCtrl, то мы должны оперировать не значениями, а свойствами объектов, то есть вместо user мы запишем user.name:

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

    9. Тестирование в ручную

    Начинающие разработчики недооценивают силу TDD и проверяют весь проект при изменении в какой-то части (ну или не проверяют, тут уже от ответственности зависит). То же самое касается приложений на основе AngularJS. А если еще учесть тот факт, что AngularJS изначально разрабатывался как “хорошо тестируемый”, а для тестирования в нашем распоряжения есть множество удобных инструментов.

    2 самых полулярных тест-ранера это Karma и Protractor. Karma используется для юнит тестов, а Protractor – для функциональных/интеграционных с подключением Selenium и имитацией “реальных” действий пользователя в браузере.

    Полезные посты по теме:

    10. Использование jQuery

    Просто прекратите использовать jQuery. Серьезно! Только так вы сможете отвыкнуть от микро-проектирования “плагинчиками” и перейти к более маштабному модульному подходу.

    Выводы

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

    Команда Angular выпустила инструменты, упрощающие переход с AngularJS на Angular

    Команда разработчиков JS-фреймворка AngularJS выпустила два пользовательских «помощника» — ngMigration Assistant и Forum. Инструменты позволяют узнать, какой переход с AngularJS на Angular является верным, как максимально упростить процесс и избежать ошибок.

    ngMigration Assistant

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

    Ниже — пример использования ngMigration Assistant для приложения AngularJS phone catalog. С помощью команды ngma , прописанной в директории, выполняется анализ и прописываются рекомендации.

    Вначале инструмент показывает статистику имеющихся данных, а после — этапы подготовки к миграции на Angular.

    ngMigration Forum

    В новом сообществе ngMigration Forum собрана актуальная информация о путях миграции и инструментах, обеспечивающих переход с AngularJS на Angular. ngMigration Forum — место для обмена опытом, решения проблем и вопросов фреймворк-экспертам.

    Последнее обновление Angular 6.1 вышло в конце июля 2020 года. В Angular была добавлена поддержка TypeScript 2.8 и 2.9, а также возможность настройки роутера на запоминание и восстановление положения прокрутки.

  • Понравилась статья? Поделиться с друзьями:
    Все языки программирования для начинающих