Angular: Observable, Subject,

Observable – это особый объект, на который можно подписываться и мониторить его изменения в реальном времени.

Документация, но в нее углубляться нет смысла, если работать только с ангуляром.

Observable Angular

Пример Observable

Простой, где мы просто получим в консоли значения 1, 2, 3… с интервалом в секунду. Здесь только подписка на него (subscribe), так как в остальных двух типах обработки нет смысла.

import { Component, OnDestroy, OnInit } from '@angular/core';

import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import { Observer } from 'rxjs/Observer';
import { Subscription } from 'rxjs/Subscription';

export class HomeComponent implements OnInit, OnDestroy { 
numbersObsSubscription: Subscription;

constructor() { }

 ngOnInit() {
    const myNumbers = Observable.interval(1000);
    
    this.numbersObsSubscription = myNumbers.subscribe(
      (number: number) => {
        console.log(number);
      }
    );
 }
}

ngOnDestroy() {
  this.numbersObsSubscription.unsuscribe();
}

В конце при уничтожении компонента обязательно отписываемся.

Более сложные, где все типы обработки задействованы:

...
customObsSubscription: Subscription;

  constructor() { }

  ngOnInit() {
    const myObservable = Observable.create((observer: Observer<string>) => {
      setTimeout(() => {
        observer.next('first package');
      }, 2000);
      setTimeout(() => {
        observer.next('second package');
      }, 4000);
      setTimeout(() => {
        // observer.error('this does not work');
        observer.complete();
      }, 5000);
      setTimeout(() => {
        observer.next('third package');
      }, 6000);
    });
    this.customObsSubscription = myObservable.subscribe(
      (data: string) => { console.log(data); },
      (error: string) => { console.log(error); },
      () => { console.log('completed'); }
    );
  }

  ngOnDestroy() {
    this.customObsSubscription.unsubscribe();
  }

Пример BehaviorSubject

Создадим простой BehaviorSubject, возвращающий по подписке данные из сервиса в компоненты.

В файле-сервисе:

rooms: Room[] = [{roomName: 'bath'}, {roomName: 'bedroom'}]

private data$$ = new BehaviorSubject<Room[]>(this.rooms); // при создании передаем первичные данные

  public getRooms$(): Observable<Room[]> {
    return this.data$$.asObservable();
  }

А в файле-компоненте подписываемся, как и на любой Observable:

 ngOnInit(): void {
    this.roomsService.getRooms$().subscribe((rooms) => (this.rooms = rooms));
}

 

Связь компонентов при помощи Subject

Это более правильный способ связи компонетов, которые не знают друг о друге, чем eventEmiter!

1. Subject в сервисе

Subject – это одновременно observable и observe (наблюдаемый и наблюдатель).Поэтому он подходит для связи двух компонентов.

Создадим Subject в сервисе /app/test.service.ts:

import { Subject } from 'rxjs';

export class TestService {
  userActivated = new Subject<someType>();
}

2. Компонент, отправляющий данные

Теперь в одном из компонент, где, например, мы используем id в качестве параметра, в шаблоне добавим кнопку:

<button (click)="ActivateObservable()">Activate observable</button>

А в классе пропишем функцию для этой кнопки, которая пушит данные в наш созданный Subject:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';

import { TestService } from '../test.service';

@Component({
  selector: 'app-location',
  templateUrl: './location.component.html',
  styleUrls: ['./location.component.scss'],
})
export class LocationComponent implements OnInit {
  id: number = 0;

  constructor(private route: ActivatedRoute, private testService: TestService) {}

  ngOnInit(): void {
    this.route.params.subscribe((params: someType) => {
      this.id = +params['id'];
      this.furnitureServices.testGetIdFromComponent(this.id);
    });
  }

  ActivateObservable() {
    this.testService.userActivated.next(this.id);
  }
}

3. Компонент, принимающий данные

Теперь, например, в компоненте, где у нас список элементов, которые имеют ссылки с этими передаваемыми id, принимаем наши данные:

import { Component, OnInit } from '@angular/core';
import { TestService } from '../test.service';

@Component({
  selector: 'app-move-detalis',
  templateUrl: './move-detalis.component.html',
  styleUrls: ['./move-detalis.component.scss'],
})
export class MoveDetalisComponent implements OnInit {
  nav1ElementActived = false;
  nav2ElementActived = false;

  constructor(private testService: TestService) {}

  ngOnInit(): void {
    this.testService.userActivated.subscribe((id: unknown | undefined) => {
      //number не проходит((
      if (id === 1) {
        this.nav1ElementActived = true;
      } else if (id === 2) {
        this.nav2ElementActived = true;
      }
    });
  }
}

В шаблоне, зависимо от активированного элемента можно что-то вывести, например слово напротив “activated”.

Операторы

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

Например, популярным оператором map обработаем приходящие данные из “простого” Observable и трансформируем их, умножив каждый результат на 2:

 ngOnInit() {
    Observable.interval(1000).pipe(
      .map(
        (data: number) => {
          return data * 2;
        }
      ));
    this.numbersObsSubscription = myNumbers.subscribe(
      (number: number) => {
        console.log(number);
      }
    );
}

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *