Angular: Observable, Subject,

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

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

Observable Angular

Пример Observable

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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();
}
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(); }
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();
}

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
...
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();
}
... 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(); }
...
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, возвращающий по подписке данные из сервиса в компоненты.

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
rooms: Room[] = [{roomName: 'bath'}, {roomName: 'bedroom'}]
private data$$ = new BehaviorSubject<Room[]>(this.rooms); // при создании передаем первичные данные
public getRooms$(): Observable<Room[]> {
return this.data$$.asObservable();
}
rooms: Room[] = [{roomName: 'bath'}, {roomName: 'bedroom'}] private data$$ = new BehaviorSubject<Room[]>(this.rooms); // при создании передаем первичные данные public getRooms$(): Observable<Room[]> { return this.data$$.asObservable(); }
rooms: Room[] = [{roomName: 'bath'}, {roomName: 'bedroom'}]

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

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ngOnInit(): void {
this.roomsService.getRooms$().subscribe((rooms) => (this.rooms = rooms));
}
ngOnInit(): void { this.roomsService.getRooms$().subscribe((rooms) => (this.rooms = rooms)); }
 ngOnInit(): void {
    this.roomsService.getRooms$().subscribe((rooms) => (this.rooms = rooms));
}

 

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

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

1. Subject в сервисе

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { Subject } from 'rxjs';
export class TestService {
userActivated = new Subject<someType>();
}
import { Subject } from 'rxjs'; export class TestService { userActivated = new Subject<someType>(); }
import { Subject } from 'rxjs';

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

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<button (click)="ActivateObservable()">Activate observable</button>
<button (click)="ActivateObservable()">Activate observable</button>
<button (click)="ActivateObservable()">Activate observable</button>

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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);
}
}
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); } }
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, принимаем наши данные:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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;
}
});
}
}
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; } }); } }
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ngOnInit() {
Observable.interval(1000).pipe(
.map(
(data: number) => {
return data * 2;
}
));
this.numbersObsSubscription = myNumbers.subscribe(
(number: number) => {
console.log(number);
}
);
}
ngOnInit() { Observable.interval(1000).pipe( .map( (data: number) => { return data * 2; } )); this.numbersObsSubscription = myNumbers.subscribe( (number: number) => { console.log(number); } ); }
 ngOnInit() {
    Observable.interval(1000).pipe(
      .map(
        (data: number) => {
          return data * 2;
        }
      ));
    this.numbersObsSubscription = myNumbers.subscribe(
      (number: number) => {
        console.log(number);
      }
    );
}

 

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

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