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

Пример Observable
Простой, где мы просто получим в консоли значения 1, 2, 3… с интервалом в секунду. Здесь только подписка на него (subscribe), так как в остальных двух типах обработки нет смысла.
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { Subscription } from 'rxjs/Subscription';
export class HomeComponent implements OnInit, OnDestroy {
numbersObsSubscription: Subscription;
const myNumbers = Observable.interval(1000);
this.numbersObsSubscription = myNumbers.subscribe(
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();
}
В конце при уничтожении компонента обязательно отписываемся.
Более сложные, где все типы обработки задействованы:
customObsSubscription: Subscription;
const myObservable = Observable.create((observer: Observer<string>) => {
observer.next('first package');
observer.next('second package');
// observer.error('this does not work');
observer.next('third package');
this.customObsSubscription = myObservable.subscribe(
(data: string) => { console.log(data); },
(error: string) => { console.log(error); },
() => { console.log('completed'); }
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, возвращающий по подписке данные из сервиса в компоненты.
В файле-сервисе:
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:
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:
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 в качестве параметра, в шаблоне добавим кнопку:
<button (click)="ActivateObservable()">Activate observable</button>
<button (click)="ActivateObservable()">Activate observable</button>
<button (click)="ActivateObservable()">Activate observable</button>
А в классе пропишем функцию для этой кнопки, которая пушит данные в наш созданный Subject:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { TestService } from '../test.service';
selector: 'app-location',
templateUrl: './location.component.html',
styleUrls: ['./location.component.scss'],
export class LocationComponent implements OnInit {
constructor(private route: ActivatedRoute, private testService: TestService) {}
this.route.params.subscribe((params: someType) => {
this.furnitureServices.testGetIdFromComponent(this.id);
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, принимаем наши данные:
import { Component, OnInit } from '@angular/core';
import { TestService } from '../test.service';
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) {}
this.testService.userActivated.subscribe((id: unknown | undefined) => {
this.nav1ElementActived = true;
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:
Observable.interval(1000).pipe(
this.numbersObsSubscription = myNumbers.subscribe(
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);
}
);
}