Статьи

Обновите ваше приложение до Angular 1.5 Components и выше!

Эта статья была рецензирована Дэном Принсом и Микаэлой Лер . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

С каждым новым выпуском AngularJS команда разработчиков пытается преодолеть разрыв между AngularJS 1.x и 2. С выпуском AngularJS 1.5 разработчики смогут писать приложения, структурно похожие на AngularJS 2.0 .

В этом уроке мы собираемся создать директиву grid в AngularJS 1.4. Затем мы пройдемся по шагам, чтобы обновить его до 1.5, а затем посмотрим, как мы можем преобразовать его для работы с версией 2.0.

Начиная

Давайте начнем с создания каталога проекта под названием AngularMigrateApp . В этой папке создайте страницу HTML с именем index.html . Вот как должна выглядеть страница:

 <!DOCTYPE html> <html lang="en" ng-app="myApp" class="no-js"> <head> <title>My AngularJS App</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> </head> <body> <script src="https://code.angularjs.org/1.4.10/angular.js"></script> </body> </html> 

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

Создание Грид Директивы

Давайте создадим простую директиву grid для отображения массива JSON. Начнем с создания модуля AngularJS.

 angular.module('myApp', []) .constant('employees', [{ firstName: 'Rima', lastName: 'George', location: 'San Francisco' }, { firstName: 'Shaun', lastName: 'John', location: 'Germany' }, { firstName: 'Rahul', lastName: 'Kurup', location: 'Bangalore' }, { firstName: 'Samson', lastName: 'Davis', location: 'Canada' }, { firstName: 'Shilpa', lastName: 'Agarwal', location: 'Noida' }]) .controller('HomeCtrl', ['$scope', 'employees', function($scope, employees) { $scope.employees = employees; }]) 

Мы определили константу с именем employees которая содержит массив примеров данных. Затем мы HomeCtrl этот массив в HomeCtrl и делаем его доступным в области видимости контроллера.

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

 .directive('myGrid', function() { return { } }) 

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

 <my-grid></my-grid> 

Итак, мы добавим параметр restrict, чтобы указать, что:

 .directive('myGrid', function() { return { restrict: 'E' } }) 

Далее мы хотим передать данные employees из представления в директиву. Итак, мы добавим это как привязку:

 .directive('myGrid', function() { return { restrict: 'E', scope: { info: '=info' } } }) 

Теперь мы сможем передать данные employees в директиву в виде атрибута:

 <my-grid info="employees"></my-grid> 

И последнее, но не менее важное: нам нужен шаблон HTML для отображения данных:

 .directive('myGrid', function() { return { restrict: 'E', scope: { info: '=info' }, templateUrl : '/directiveGrid.html' } }) 

Добавьте следующий скрипт HTML-шаблона в тело index.html .

 <script type="text/ng-template" id="/directiveGrid.html"> <div class="panel panel-primary"> <div class="panel-heading">Site Point Directive Grid</div> <table class="table"> <thead> <tr> <th>FirstName</th> <th>Last Name</th> <th>Location</th> </tr> </thead> <tbody> <tr ng-repeat="employee in info"> <td>{{ employee.firstName }}</td> <td>{{ employee.lastName }}</td> <td>{{ employee.location }}</td> </tr> </tbody> </table> </div> </script> 

Как видно из приведенного выше кода, мы перебираем свойство info и отображаем каждый из элементов в списке сотрудников.

Давайте использовать директиву myGrid внутри index.html . Добавьте следующий код:

 <div ng-controller="HomeCtrl"> <my-grid info="employees"></my-grid> </div> 

Мы указали контроллер HomeCtrl и внутри него использовали нашу директиву. Сохраните изменения и перейдите на страницу index.html . Вот демонстрация сетки данных в действии:

Обновление до 1.5

Пока что мы создали директиву AngularJS, используя версию 1.4, и она работает довольно хорошо. Теперь давайте попробуем использовать тот же код с AngularJS 1.5 и посмотрим, не сломается ли что-нибудь.

Давайте заменим существующую ссылку на скрипт ссылкой CDN на версию 1.5 . Если вы попытаетесь обновить страницу, все должно работать нормально. С этим новым выпуском линейки 1.x инфраструктура приближается к тому, как AngularJS 2.0 будет работать, используя компоненты , и мы можем воспользоваться этим в нашем коде, упрощая возможный переход на версию 2.0.

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

При работе с AngularJS разработчики, как правило, склонны работать с подходом, основанным на контроллерах, но это может создать много проблем по мере роста приложения. Подход, основанный на контроллере и представлении, приводит к повторяющемуся ng-controller / view, но подход, основанный на компонентах, решает проблему путем создания компонентов, которые могут быть составлены в более крупные компоненты без повторения кода.

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

 .component('myDataComp', {}); 

В отличие от метода директивы, который принимает функцию, метод компонента принимает объект. Мы передадим те же объекты, что и в нашей директиве, с другим шаблоном. Вот HTML-шаблон:

 <script type="text/ng-template" id="/componentGrid.html"> <div class="panel panel-primary"> <div class="panel-heading">Site Point Directive Grid</div> <table class="table"> <thead> <tr> <th>FirstName</th> <th>Last Name</th> <th>Location</th> </tr> </thead> <tbody> <tr ng-repeat="employee in info"> <td>{{ employee.firstName }}</td> <td>{{ employee.lastName }}</td> <td>{{ employee.location }}</td> </tr> </tbody> </table> </div> </script> 

Вот модифицированный код компонента:

 .component('myComp', { restrict: 'E', scope: { info: '=info' }, templateUrl : '/componentGrid.html' }); 

Как видно из приведенного выше кода, мы передали все параметры, которые были в нашей старой директиве.

Создайте компонент myComp на странице index.html .

 <div ng-controller="HomeCtrl"> <my-grid info="employees"></my-grid> <my-comp info="employees"></my-comp> </div> 

Сохраните изменения и обновите страницу, и вы увидите, что данные не отображаются, но в консоли браузера также нет ошибок.

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

Сравнение директив и компонентов

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

Вот модифицированный код:

  .component('myComp', { bindings: { info: '=info' }, templateUrl : '/componentGrid.html' }); 

Информация о привязке будет привязана к контроллеру. Псевдоним по умолчанию для контроллера — $ctrl и внутри шаблона мы будем использовать его для доступа к свойству info :

 <script type="text/ng-template" id="/componentGrid.html"> <div class="panel panel-primary"> <div class="panel-heading">Site Point Component Grid</div> <table class="table"> <thead> <tr> <th>FirstName</th> <th>Last Name</th> <th>Location</th> </tr> </thead> <tbody> <tr ng-repeat="employee in $ctrl.info"> <td>{{ employee.firstName }}</td> <td>{{ employee.lastName }}</td> <td>{{ employee.location }}</td> </tr> </tbody> </table> </div> </script> 

Теперь, если вы обновите страницу, вы сможете просматривать данные, отображаемые с myComp компонента myComp .

Обновление до 2.0

Примечание: AngularJS 2.0 все еще находится в бета-версии. Мы используем версию Angular2.0.0-beta.8 .

Давайте заменим существующую версию AngularJS в нашем приложении ссылкой на версию 2.0 из CDN и посмотрим, не сломается ли что-нибудь:

 <script src="https://code.angularjs.org/2.0.0-beta.8/angular2.js"></script> 

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

Ошибка после включения скрипта AngularJS 2.

Как видите, наш код компонента не работал с Angular 2.0!

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

Принимая во внимание, что можно начать работу с Angular 1.x, включив фреймворк с одним тегом script, ситуация с Angular 2.0 изменилась. Нам нужна пара других библиотек, чтобы функционировать. Хотя их загрузка через теги скрипта в порядке для разработки, они предназначены для объединения как часть процесса сборки для производства.

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

Давайте создадим папку с именем AngularJS2.0Component и создадим файл package.json следующим образом:

 { "name": "angular2-quickstart", "version": "1.0.0", "scripts": { "start": "npm run lite", "lite": "lite-server" }, "license": "ISC", "dependencies": { "bootstrap": "^3.3.6", "angular2": "2.0.0-beta.8", "es6-promise": "^3.0.2", "es6-shim": "^0.33.3", "reflect-metadata": "0.1.2", "rxjs": "5.0.0-beta.2", "zone.js": "0.5.15" }, "devDependencies": { "concurrently": "^2.0.0", "lite-server": "^2.1.0" } } 

В приведенном выше файле показаны все зависимости, необходимые для приложения AngularJS 2.0. Сохраните изменения и установите необходимые зависимости, используя npm:

 npm install 

Создайте подпапку с именем app и внутри создайте файл app.component.js со следующим кодом:

 (function(app) { app.AppComponent = ng.core.Component({ selector: 'my-comp', templateUrl: 'grid.html' }) .Class({ constructor: function() { this.employees = [{ firstName: 'Rima', lastName: 'George', location: 'San Francisco' }, { firstName: 'Shaun', lastName: 'John', location: 'Germany' }, { firstName: 'Rahul', lastName: 'Kurup', location: 'Bangalore' }, { firstName: 'Samson', lastName: 'Davis', location: 'Canada' }, { firstName: 'Shilpa', lastName: 'Agarwal', location: 'Noida' }]; } }); })(window.app || (window.app = {})); 

В приведенном выше коде мы используем базовое пространство имен Angular ng.core для создания компонента. Мы определили селектор для нашего компонента как my-comp . Мы используем тот же HTML, grid.html , что и шаблон для нашего приложения. Мы определили объект наших employees в конструкторе компонента.

Создайте файл с именем main.js и вставьте следующий код:

 (function(app) { document.addEventListener('DOMContentLoaded', function() { ng.platform.browser.bootstrap(app.AppComponent); }); })(window.app || (window.app = {})); 

Это говорит Angular загрузить компонент, который мы только что создали.

Затем создайте файл index.html вне папки приложения и вставьте следующий код:

 <html> <head> <title>Angular Component</title> <link rel="stylesheet" href="styles.css"> <link rel="stylesheet" type="text/css" href="node_modules/bootstrap/dist/css/bootstrap.min.css"> <!-- 1. Load libraries --> <!-- IE required polyfill --> <script src="node_modules/es6-shim/es6-shim.min.js"></script> <script src="node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script> <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script> <script src="node_modules/rxjs/bundles/Rx.umd.js"></script> <script src="node_modules/angular2/bundles/angular2-all.umd.js"></script> <!-- 2. Load our 'modules' --> <script src='app/app.component.js'></script> <script src='app/main.js'></script> </head> <!-- 3. Display the application --> <body> <my-comp>Loading...</my-comp> </body> </html> 

Приведенная выше страница index.html является начальным шаблоном для приложений AngularJS 2.0. Мы включили все необходимые зависимости, и в теге body мы использовали наш компонент.

Сохраните изменения и запустите сервер, используя npm start . Эта команда запускает локальный сервер разработки, называемый lite-server который загружает index.html в браузер.

Но все же данные не отображаются!

В AngularJS 2.0 синтаксис зацикливания немного отличается. Измените часть цикла в grid.html как показано ниже:

 <tr *ngFor="#employee of employees"> 

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

Завершение

Компоненты являются основной частью AngularJS 2.0, и было бы правильно сказать, что это основанная на компонентах инфраструктура. С каждым новым выпуском линии 1.x мы приближаемся к тому, как разрабатываются приложения с использованием версии 2.0.

В этом уроке мы создали директиву AngularJS, используя версию 1.4 платформы. Мы переделали директиву, чтобы воспользоваться синтаксисом компонентов версии 1.5. Наконец, мы обновили его до версии Angular 2.0.

Для более подробного изучения миграции приложений AngularJS, ознакомьтесь с официальным руководством по миграции . Код Angular 2 также может быть написан на TypeScript и Dart, и если вам интересно, я бы рекомендовал прочитать официальное руководство по началу работы с AngularJS 2 на TypeScript или Dart соответственно.

Поделитесь своими мыслями и предложениями в комментариях ниже!