Update Docs - Observables
This commit is contained in:
parent
2232f4247f
commit
2972c596d9
@ -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.
|
||||
|
||||
<img src="../img/observable.png" alt="component" width="800"/>
|
||||
|
||||
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.
|
||||
|
||||
<img src="../img/observable_operator.png" alt="component" width="800"/>
|
||||
|
||||
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.
|
||||
|
||||
<img src="../img/rxjs_subject.png" alt="component" width="800"/>
|
||||
|
||||
> 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<boolean>();
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
...
|
||||
<p *ngIf="userActivated">Activated!</p>
|
||||
...
|
||||
```
|
||||
|
||||
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
|
||||
<button class="btn btn-primary" (click)="onActivate()">Activate</button>
|
||||
```
|
||||
|
||||
## Ressource
|
||||
|
||||
[RxJS](https://rxjs-dev.firebaseapp.com/)
|
BIN
img/observable.png
Normal file
BIN
img/observable.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 147 KiB |
BIN
img/observable_operator.png
Normal file
BIN
img/observable_operator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 93 KiB |
BIN
img/rxjs_subject.png
Normal file
BIN
img/rxjs_subject.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 145 KiB |
Loading…
Reference in New Issue
Block a user