diff --git a/docs/observables.md b/docs/observables.md index e69de29..80f344e 100644 --- a/docs/observables.md +++ b/docs/observables.md @@ -0,0 +1,235 @@ +# Observables + +Observable emmits an event driven by the data source. + +Observer subscribe to the observable to be notified when an event is emitted. + +This is an asynchronous operation. + +component + +It can also used promises or callbacks to achieve the same result. Observable is just an other approach. + +## Install RxJS + +```bash +npm install --save rxjs@6 + +npm install --save rxjs-compat +``` + +## Example and general usage + +In this case `params` is an observable which we can subscribe to. + +```ts +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; + +@Component({ + selector: 'app-user', + templateUrl: './user.component.html', + styleUrls: ['./user.component.css'] +}) +export class UserComponent implements OnInit { + id: number; + + constructor(private route: ActivatedRoute) { + } + + ngOnInit() { + this.route.params.subscribe((params: Params) => { + this.id = +params.id; + }); + } +} +``` + +It exists various types of observable. +- executed once +- executed periodically +- ... + +```ts +import { interval } from 'rxjs'; + +interval(1000).subscribe( count => { + consol.log(count); +}) +``` + +`interval` is a built-in observable from rxjs. + +If the app **don't** `unsubscribe` from the observable can cause **memory leaks**. Also, if we navigate to an other route, countless observable will be created and couses performance issues. + +When we leave the component we can call the `OnDestroy` function to unsubscribe from the observable. + +```ts +import { Component, OnDestroy, OnInit } from '@angular/core'; + +import { interval, Subscription, Observable } from 'rxjs'; + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.css'] +}) +export class HomeComponent implements OnInit, OnDestroy { + + private firstObsSubscription: Subscription; + + constructor() {} + + ngOnInit() { + this.firstObsSubscription = interval(1000).subscribe(count => { + console.log(count); + }); + + ngOnDestroy(): void { + this.firstObsSubscription.unsubscribe(); + } +} +``` + +In this example, the first subscription is stored in `firstObsSubscription` variable, which at leaving the component will be destroyed by calling `unsubscribe()`. + +> Note: For all Angular built-in observables, is not necessary to unsubscribe from the observable. This is handleb by Angular itself. + +## Building an observable (data, error, complete) + +```ts +const customIntervalObservable = Observable.create(observer => { + let count = 0; + setInterval(() => { + observer.next(count); + if (count === 5) { + observer.complete(); + } + if (count > 3) { + observer.error(new Error('Count is greater 3!')); + } + count++; + }, 1000); +}); + +this.firstObsSubscription = customIntervalObservable.subscribe(data => { + console.log(data); +}, error => { + console.log(error); + alert(error.message); +}, () => { + console.log('Completed!'); +}); +``` + +The `subscribe` function accepts up to three arguments: `data`, `error` and `complete`. + +> Note: if the observable is completed, is not necessary to `unsubscribe`. + +> Note: If an error is thrown, the observable is *cancelled* but not *completed*. + +## Operators + +Operators are grate to transform our data. The application can then subscribe to the result of the operator. On the operator can be called the `pipe()` function. Every operator has such a method. This function depends on the `rxjs/operators` pakage. + +component + +This is usefull when the application is fetching data from the server and it should trandformed before the component will use it. + +## Subjec + +Subject from RxJS is a more active then the event emitter because it can be called the function `next()` from the outside. + +component + +> Subject is the recommended way to emit events. + +### Subject Example + +user.service.ts +```ts +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs'; + +@Injectable({providedIn: 'root'}) +export class UserService { + activatedEmitter = new Subject(); +} +``` + +app.component.ts +```ts +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs'; + +import { UserService } from './user.service'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent implements OnInit, OnDestroy { + userActivated = false; + private activatedSub: Subscription; + + constructor(private userService: UserService) { + } + + ngOnInit() { + this.activatedSub = this.userService.activatedEmitter.subscribe(didActivate => { + this.userActivated = didActivate; + }); + } + + ngOnDestroy(): void { + this.activatedSub.unsubscribe(); + } +} +``` + +app.component.html +```html +... +

Activated!

+... +``` + +user.component.ts +```ts +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; + +import { UserService } from '../user.service'; + +@Component({ + selector: 'app-user', + templateUrl: './user.component.html', + styleUrls: ['./user.component.css'] +}) +export class UserComponent implements OnInit { + id: number; + + constructor(private route: ActivatedRoute, private userService: UserService) { + } + + ngOnInit() { + this.route.params.subscribe((params: Params) => { + this.id = +params.id; + }); + } + + onActivate() { + this.userService.activatedEmitter.next(true); + } +} +``` + +user.component.html +```html + +``` + +## Ressource + +[RxJS](https://rxjs-dev.firebaseapp.com/) \ No newline at end of file diff --git a/img/observable.png b/img/observable.png new file mode 100644 index 0000000..c1f5771 Binary files /dev/null and b/img/observable.png differ diff --git a/img/observable_operator.png b/img/observable_operator.png new file mode 100644 index 0000000..5aa349e Binary files /dev/null and b/img/observable_operator.png differ diff --git a/img/rxjs_subject.png b/img/rxjs_subject.png new file mode 100644 index 0000000..72e3d21 Binary files /dev/null and b/img/rxjs_subject.png differ