Angular:Observable

folder Projet: angularApp
Observable une classe du modul RxJS Library permet gérer le flux des données reçus d'une manière asynchrone ,car lorsque on appel un traitement externe sa poura prendre quelque seconds donc afin de ne pas bloquer les traitement en attendant la reponse ,obeservable permet d'attends les données puis les traité en utilisant les fonctions :next(), error() & complete()
npm install --save rxjs-compat

Exemple:

obs = new Observable((observer) => {
console.log("Observable starts")
observer.next("données1") //recevoir les données un un
observer.next("données2")//le temps entre chaque données reçue est aléatoire
observer.next("données3")
observer.error("error délenchée") //le traiment du flux de données est arrêté
observer.next("données4")
})
Afin de consomer un objet observable on appel la fonction subscribe()

app.component.ts

import { Component } from '@angular/core';
import { Observable } from 'rxjs';


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})


export class AppComponent {
obs = new Observable((observer) => {
console.log("Observable starts")
observer.next("données1");
observer.next("données2");
observer.next("données3");
observer.next("données4");
observer.complete();
})
data : any = [];
ngOnInit() {
this.obs.subscribe(
val=> { this.data.push(val) },
error => { console.log("error")},
() => {console.log("Completed")}
)
}
}

app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">
<ul class="list-group">
<li class="list-group-item" *ngFor="let v of data; let i = index">
{{v}}
</li>
</ul>

</div>

Opérateur of()

Permet de créer un observable à partir d'un liste de valeur ou un Array

app.component.ts

import { Component } from '@angular/core';
import { Observable,of } from 'rxjs';


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
data : any = [];
ngOnInit() {
const t=['a','b','c','d','e','f','g'] ;
const obOF=of("1","2","3",true,15,t,"hello world" );
obOF.subscribe(val => this.data.push(val),
error=> console.log("error"),
() => console.log("complete"))

}
}

Résultats

1
2
3
true
15
a,b,c,d,e,f,g
hello world

Opérateur from(array)

Permet de créer un observable à partir d'un liste de valeur ou un Array
1.avec Array

app.component.ts

import { Component } from '@angular/core';
import { Observable,of,from } from 'rxjs';


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
data : any = [];
ngOnInit() {
const t=['a','b','c','d','e','f','g'] ;
const obOF=from(t);
obOF.subscribe(val => this.data.push(val),
error=> console.log("error"),
() => console.log("complete"))

}
}

Résultats

a
b
c
d
e
f
g
1.avec Array

app.component.ts

import { Component } from '@angular/core';
import { Observable,of,from } from 'rxjs';


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
data : any = [];
ngOnInit() {
const t="Thank you" ;
const obOF=from(t);
obOF.subscribe(val => this.data.push(val),
error=> console.log("error"),
() => console.log("complete"))
}
}

Résultats

T
h
a
n
k
y
o
u

Observable pipe

filter et map

app.component.ts

import { Component } from '@angular/core';
import { Observable,of,from } from 'rxjs';
import { map, filter, tap } from 'rxjs/operators'


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
data : any = [];
obs = new Observable<number>((observer) => {
observer.next(1)
observer.next(2)
observer.next(3)
observer.next(4)
observer.next(5)
observer.complete()
}).pipe(
filter(v => v > 2),//récupéer seulement les données dont val>2
map((val) => {return val as number * 2}),//traiter puis mapper les données
)
ngOnInit() {
this.obs.subscribe(
val=> { this.data.push(val) },
error => { console.log("error")},
() => {console.log("Completed")}
)
}

}

Observable and HttpClient :lazy loading

Obsevalble est utilsé afin de consomer un service dans un serveur distant en utilisant HttpClient
Afin d'utiliser Observable on a deux méthode:
  1. avec le symbole : $
  2. Avec la méthode : subscribe()

Avec subscribe()

on va créer un service qui permet de consomer l'api https://jsonplaceholder.typicode.com/posts

post.service.ts

ng g service post

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class PostService {
private url: string = 'https://jsonplaceholder.typicode.com/posts';
constructor(private httpClient: HttpClient) { }
public getPosts(): Observable<Post[]>{
return this.httpClient.get<Post[]>(this.url);
}
}

export class Post {
constructor(
public body: string,
public id: number,
public title: string,
public userId: number
) {}
}

app.component.ts

import { Component } from '@angular/core';
import { Observable,of,from } from 'rxjs';
import { map, filter, tap } from 'rxjs/operators'
import { PostService } from "./album.service"


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
name = 'Angular';
posts = new Array<Post>();
constructor(private service:PostService) {}
ngOnInit() {
this.service.getPosts().subscribe(response => {
this.posts = response.map(item =>
{
return new Post(
item.body,
item.id,
item.title,
item.userId
);
});
});
}
}


export class Post {
constructor(
public body: string,
public id: number,
public title: string,
public userId: number
) {}
}

app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">
<ul class="list-group">
<li class="list-group-item" *ngFor="let post of posts">
{{ post.title }}
</li>
</ul>
</div>

Avec $

Permet de subscribe automatiquement à une Observable

app.component.ts

import { Component } from '@angular/core';
import { Observable,of,from } from 'rxjs';
import { map, filter, tap } from 'rxjs/operators'
import { PostService } from "./album.service"


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
public posts$!: Observable<Post[]>
constructor(private service:PostService) {}
public ngOnInit() {
this.posts$ = this.service.getPosts()
}
}


export class Post {
constructor(
public body: string,
public id: number,
public title: string,
public userId: number
) {}
}

app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">
<ul class="user__list" *ngIf="(posts$ | async)!.length">
<li class="user" *ngFor="let user of posts$ | async ; else loading">
{{ user.title }}
</li>
</ul>
<ng-template #loading>
Loading...
</ng-template>
</div>