javascript

Книга «Angular 4 для профессионалов»

  • среда, 25 октября 2017 г. в 03:13:15
https://habrahabr.ru/company/piter/blog/340826/
  • Разработка веб-сайтов
  • JavaScript
  • AngularJS
  • Блог компании Издательский дом «Питер»


image Выжмите из Angular — ведущего фреймворка для динамических приложений JavaScript — всё. Адам Фримен начинает с описания MVC и его преимуществ, затем показывает, как эффективно использовать Angular, охватывая все этапы, начиная с основ и до самых передовых возможностей, которые кроются в глубинах этого фреймворка.

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

Об авторе


Адам Фримен (Adam Freeman) — опытный профессионал в области IT, занимавший руководящие должности во многих компаниях. До недавнего времени он занимал посты технического директора и главного инженера в одном из крупнейших банков. Сейчас Адам посвящает свое время в основном написанию книг и бегу на длинные дистанции.

О научном редакторе


Фабио Клаудио Феррачиати (Fabio Claudio Ferracchiati) — старший консультант и ведущий аналитик/разработчик с опытом использования технологий Microsoft. Он работает на BluArancio (www.bluarancio.com). Фабио является сертифицированным разработчиком программных решений для .NET, сертифицированным разработчиком приложений для .NET, сертифицированным профессионалом Microsoft, плодовитым писателем и научным редактором. За последние 10 лет он написал ряд статей для итальянских и международных журналов и участвовал в написании более 10 книг по различным областям компьютерной тематики.

Подготовка проекта Angular
Обновление корневого компонента


Начнем с корневого компонента — структурного блока Angular, который будет управлять элементом app в документе HTML. Приложение может содержать несколько компонентов, но среди них всегда присутствует корневой компонент, отвечающий за отображение контента верхнего уровня. Отредактируйте файл app.component.ts в папке SportsStore/src/app и включите в него код из листинга 7.5.

Листинг 7.5. Содержимое файла app.component.ts в папке SportsStore/src/app

import { Component } from "@angular/core";

@Component({
         selector: "app",
         template: `<div class="bg-success p-a-1 text-xs-center">
                                 This is SportsStore
                          </div>`
})
export class AppComponent { }

Декоратор Component сообщает Angular, что класс AppComponent является компонентом, а его свойства описывают применение этого компонента. Полный набор свойств компонентов приведен в главе 17, но три свойства, приведенные в листинге, являются основными и часто применяемыми на практике. Свойство selector сообщает Angular, как следует применять компонент в документе HTML, а свойство template определяет контент, который будет отображаться компонентом. Компоненты могут определять встроенные шаблоны, как в данном случае, или использовать внешние файлы HTML, которые упрощают управление сложным контентом.

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

Обновление корневого модуля


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

Корневой модуль передает описание приложения для Angular. В описании указано, какие функциональные модули необходимы для запуска приложения, какие нестандартные возможности следует загрузить и как называется корневой компонент. Традиционно файлу корневого компонента присваивается имя app.module.ts; создайте файл с таким именем в папке SportsStore/src/app и включите код из листинга 7.6.

Листинг 7.6. Содержимое файла app.module.ts в папке SportsStore/src/app

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";

@NgModule({
          imports: [BrowserModule],
          declarations: [AppComponent],
          bootstrap: [AppComponent]
})
export class AppModule { }

По аналогии с корневым компонентом класс корневого модуля не содержит код. Дело в том, что корневой модуль существует только для передачи информации через декоратор @NgModule. Свойство imports приказывает Angular загрузить функциональный модуль BrowserModule со всей основной функциональностью Angular, необходимой для веб-приложения.

Свойство declarations приказывает Angular загрузить корневой компонент, а свойство bootstrap сообщает, что корневым компонентом является класс AppModule. Информация будет добавлена в свойства этого декоратора при включении функциональности в приложение SportsStore, но для запуска приложения будет достаточно и базовой конфигурации.

Анализ файла начальной загрузки


Следующий блок служебного кода — файл начальной загрузки, запускающий приложение. В книге основное внимание уделяется применению Angular для создания приложений, работающих в браузерах, но платформа Angular может портироваться в разные среды. Файл начальной загрузки использует браузерную платформу Angular для загрузки корневого модуля и запуска приложения. Создайте файл с именем main.ts, традиционно назначаемым файлу начальной загрузки, в папке SportsStore/src/app и добавьте в него код из листинга 7.7.

Листинг 7.7. Содержимое файла main.ts в папке SportsStore/src

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
    enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule);

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

image

Просматривая модель DOM в браузере, вы увидите, что временный контент из шаблона корневого компонента был вставлен между начальным и конечным тегами элемента app:

<body class="m-a-1">
       <app>
               <div class="bg-success p-a-1 text-xs-center">
                     This is SportsStore
               </div>
       </app>
</body>

Начало работы над моделью данных


Работу над любым новым проектом лучше всего начинать с модели данных. Я хочу поскорее продемонстрировать некоторые возможности Angular в действии, поэтому вместо определения модели данных от начала до конца мы начнем с реализации базовой функциональности на фиктивных данных. Затем эти данные будут использованы для создания интерфейсной части, а в главе 8 мы вернемся к модели данных и свяжем ее с REST-совместимой веб-службой.

Создание классов модели


Каждой модели данных необходимы классы для описания типов данных, входящих в модель данных. В приложении SportsStore это классы с описанием товаров, продаваемых в интернет-магазине, и заказы, полученные от пользователей. Для начала работы приложения SportsStore достаточно возможности описания товаров; другие классы моделей будут создаваться для поддержки расширенной функциональности по мере их реализации. Создайте файл с именем product.model.ts в папке SportsStore/src/app/model и включите код из листинга 7.8.

Листинг 7.8. Содержимое файла product.model.ts из папки SportsStore/src/app/model

export class Product {

       constructor(
             public id?: number,
             public name?: string,
             public category?: string,
             public description?: string,
             public price?: number) { }
}

Класс Product определяет конструктор, который получает свойства id, name, category, description и price. Эти свойства соответствуют структуре данных, используемых для заполнения REST-совместимой веб-службы в листинге 7.2. Вопросительные знаки (?) за именами параметров указывают, что это необязательные параметры, которые могут быть опущены при создании новых объектов с использованием класса Product; это может быть удобно при разработке приложений, свойства объектов модели которых заполняются с использованием форм HTML.

Создание фиктивного источника данных


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

Создайте файл static.datasource.ts в папке SportsStore/src/app/model и включите определение класса из листинга 7.9.

Листинг 7.9. Содержимое файла static.datasource.ts из папки SportsStore/src/app/model

import { Injectable } from "@angular/core";
import { Product } from "./product.model";
import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/from";

@Injectable()
export class StaticDataSource {
       private products: Product[] = [
             new Product(1, "Product 1", "Category 1", "Product 1 (Category 1)", 100),
             new Product(2, "Product 2", "Category 1", "Product 2 (Category 1)", 100),
             new Product(3, "Product 3", "Category 1", "Product 3 (Category 1)", 100),
             new Product(4, "Product 4", "Category 1", "Product 4 (Category 1)", 100),
             new Product(5, "Product 5", "Category 1", "Product 5 (Category 1)", 100),
             new Product(6, "Product 6", "Category 2", "Product 6 (Category 2)", 100),
             new Product(7, "Product 7", "Category 2", "Product 7 (Category 2)", 100),
             new Product(8, "Product 8", "Category 2", "Product 8 (Category 2)", 100),
             new Product(9, "Product 9", "Category 2", "Product 9 (Category 2)", 100),
             new Product(10, "Product 10", "Category 2", "Product 10 (Category 2)", 100),
             new Product(11, "Product 11", "Category 3", "Product 11 (Category 3)", 100),
             new Product(12, "Product 12", "Category 3", "Product 12 (Category 3)", 100),
             new Product(13, "Product 13", "Category 3", "Product 13 (Category 3)", 100),
             new Product(14, "Product 14", "Category 3", "Product 14 (Category 3)", 100),
             new Product(15, "Product 15", "Category 3", "Product 15 (Category 3)", 100),
        ];

        getProducts(): Observable<Product[]> {
               return Observable.from([this.products]);
        }
}

Класс StaticDataSource определяет метод с именем getProducts, который возвращает фиктивные данные. Вызов метода getProducts возвращает результат Observable<Product[]> — реализацию Observable для получения массивов объектов Product.

Класс Observable предоставляется пакетом Reactive Extensions, который используется Angular для обработки изменений состояния в приложениях. Класс Observable будет описан в главе 23, а в этой главе достаточно знать, что объект Observable похож на объект JavaScript Promise: он представляет асинхронную задачу, которая в будущем должна вернуть результат. Angular раскрывает использование объектов Observable для некоторых своих функций, включая работу с запросами HTTP; именно поэтому метод getProducts возвращает Observable<Product[]> вместо возвращения данных — простого синхронного или с использованием Promise.

Декоратор @Injectable применяется к классу StaticDataSource. Этот декоратор сообщает Angular, что этот класс будет использоваться как служба, что позволяет другим классам обращаться к его функциональности через механизм внедрения зависимостей, описанный в главах 19 и 20. Когда приложение начнет обретать форму, мы покажем, как работает служба.

Создание репозитория модели


Источник данных должен предоставить приложению запрашиваемые данные, но обращение к данным обычно происходит через посредника (репозиторий), отвечающего за передачу этих данных отдельным структурным блокам приложения, чтобы подробности получения данных оставались скрытыми. Создайте файл product.repository.ts в папке SportsStore/src/app/model и определите класс из листинга 7.10.

Листинг 7.10. Содержимое файла product.repository.ts из папки SportsStore/app/model

import { Injectable } from "@angular/core";
import { Product } from "./product.model";
import { StaticDataSource } from "./static.datasource";

@Injectable()
export class ProductRepository {
       private products: Product[] = [];
       private categories: string[] = [];

       constructor(private dataSource: StaticDataSource) {
             dataSource.getProducts().subscribe(data => {
                    this.products = data;
                    this.categories = data.map(p => p.category)
                         .filter((c, index, array) => array.indexOf(c) == index).sort();
             });
        }

        getProducts(category: string = null): Product[] {
              return this.products
                    .filter(p => category == null || category == p.category);
        }

        getProduct(id: number): Product {
               return this.products.find(p => p.id == id);
         }

         getCategories(): string[] {
                return this.categories;
         }
}

Когда Angular потребуется создать новый экземпляр репозитория, Angular анализирует класс и видит, что для вызова конструктора ProductRepository и создания нового объекта ему нужен объект StaticDataSource. Конструктор репозитория вызывает метод getProducts источника данных, после чего использует метод subscribe объекта Observable, возвращаемого для получения данных товаров. За подробностями о работе объектов Observable обращайтесь к главе 23.

» Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок

Для Хаброжителей скидка 20% по купону — Angular