#6 Angular2. Тур героев. Сервисы

poster
В этом уроке мы научимся создавать сервисы, выносить работу с данными в них и работать с промисами в туре героев angular 2.
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

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

Сейчас у нас список героев находится в AppComponent. Вот здесь внизу. В этом есть 2 очевидных минуса. Первое - инициализировать героев это не работа компонента. Второе - мы не можем легко шарить эти данные между разными компонентами и шаблонами.

Поэтому давайте создадим сервис для того, чтобы хранить данные о наших героях. Создадим файл hero.service.ts. Внутри напишем вот такой код.

import {Injectable} from 'angular2/core';

@Injectable()
export class HeroService {
}

Мы создали класс HeroService и экспортировали его. Теперь мы можем импортировать его в любом месте, где нам необходимо. Так же мы импортировали Injectable из angular core и применили этот декоратор к нашему классу. Очень важно не забыть круглые скобки когда пишем декоратор Injectable, а то потом очень сложно отдебажить проблему.

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

Теперь давайте добавим метод для получения героев

@Injectable()
export class HeroService {
  getHeroes() {
  }
}

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

Теперь давайте перенесем массив героев из AppComponent в mock файл. Создадим файл mock-heroes.ts.

import {Hero} from './hero';
export var HEROES: Hero[] = [
    {"id": 11, "name": "Mr. Nice"},
    {"id": 12, "name": "Narco"},
    {"id": 13, "name": "Bombasto"},
    {"id": 14, "name": "Celeritas"},
    {"id": 15, "name": "Magneta"},
    {"id": 16, "name": "RubberMan"},
    {"id": 17, "name": "Dynama"},
    {"id": 18, "name": "Dr IQ"},
    {"id": 19, "name": "Magma"},
    {"id": 20, "name": "Tornado"}
];

Мы импортировали класс Hero и описали наш массив героев. Теперь мы можем использовать эти тестовые данные где угодно. В данном случае мы будем их использовать в нашем сервисе.

Теперь нам нужно пофиксить наш класс AppComponent, потому что мы оттуда убрали heroes. Изменим переменную на такую запись.

heroes: Hero[]

Теперь давайте доделаем наш сервис.

import {HEROES} from './mock-heroes';
import {Injectable} from 'angular2/core';

@Injectable()
export class HeroService {
  getHeroes() {
    return HEROES;
  }
}

Мы импортировали героев из mock файла и вернули их в методе getHeroes.

Теперь давайте поговорим о подключении нашего сервиса в AppComponent. Мы бы могли импортировать наш сервис с помощью import, как мы делали со всеми другими файлами, создать его экземпляр и с ним работать, но это не ангулар вей. Для подключения сервисов в ангуларе их нужно инджектить. Вот как это делается в angular 2.

Для этого в AppComponent, в нашем классе напишем конструктор.

constructor(private _heroService: HeroService) { }

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

Но это еще не все. Теперь нам нужно указать в провайдерах наш сервис

providers: [HeroService]

Это массив провайдеров, который говорит ангулару создавать новый екземпляр класса HeroService когда создается новый AppComponent. Нужно помнить, что все компоненты создаются в виде дерева, начиная с AppComponent. Поэтому сервис нужно подключать с помощью providers только 1 раз в нашем приложении и только в AppComponent.

Теперь давайте импортируем HeroService сверху так же, как мы импортировали остальные классы.

import {HeroService} from './hero.service';

Теперь создадим метод в котором будет получать героев и записывать в this.heroes. Для этого создаем новый метод getHeroes.

getHeroes() {
   this.heroes = this._heroService.getHeroes();
}

Следующий вопрос где вызывать получение героев. В первом ангуларе это делалось в конструкторе. В втором ангуларе для это существует специальный метод ngOnInit.

import {OnInit} from 'angular2/core';

export class AppComponent implements OnInit {
  ngOnInit() {
  }
}

Импортируем OnInit. Это интерфейс, который будет расширять наш класс. И опишем метод ngOnInit. Этот метод будет вовремя вызываться ангуларом при создании нашего компонента.

Теперь внутри нашего метода мы можем просто вызвать

this.getHeroes();

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

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

Давайте изменим код метода getHeroes в сервисе.

getHeroes() {
  return Promise.resolve(HEROES);
}

Что это меняет? Это возвращает нам теперь промис, а не данные. И именно поэтому мы можем подписываться на них с помощью колбека then.

Теперь нам нужно изменить код в AppComponent так как мы получим при выполнении метода промис, а не массив. Давайте изменим метод getHeroes в AppComponent.

getHeroes() {
  this._heroService.getHeroes().then(heroes => this.heroes = heroes);
}

Мы написали в методе then функцию, в которой мы на вход получаем наших героев и записываем их в переменную this.heroes. По сути мы переписали код и делает он тоже самое, что и раньше, но теперь он может работать с промисами. И если у нас будет промис от рестапи, то код все так же будет работать.

Если мы проверим в браузере, то наше приложение все так же работает.

На сегодня все, а в следующий раз мы поговорим о роутинге в нашем приложении.

Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.
Serafim
6 месяцев назад
Привет, чем отличается extends Component от implements OnInit ? Спасибо
monsterlessons
6 месяцев назад
Привет. Это если сравнивать Реакт и Angular? extends Component добавляет все методы класса Component, такие, как componentDidMount, componentWillReceiveProps и кучу других, так как extends это просто прототипное наследование parent/child. implements OnInit требует от нашего класса иметь interface OnInit, хотя это не прототипное наследование, а просто задание интерфейса на инстанс. Вот тут можете почитать подробнее: https://stackoverflow.com/questions/38834625/whats-the-difference-between-extends-and-implements-in-typescript