Ajout d'un exemple pour les appels http.

This commit is contained in:
Florian THIERRY
2023-02-21 15:25:03 +01:00
parent 4002d4226a
commit cfd4838d17
18 changed files with 243 additions and 13 deletions

View File

@@ -4,12 +4,17 @@ import {PromisesExampleComponent} from "./promises-example/promises-example.comp
import {HomeComponent} from "./home/home.component";
import {ObservablesExampleComponent} from "./observables-example/observables-example.component";
import {StateManagementExampleComponent} from "./state-management-example/state-management-example.component";
import {NetworkCallComponent} from "./network-call/network-call.component";
const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'network-call',
component: NetworkCallComponent
},
{
path: 'promises',
component: PromisesExampleComponent

View File

@@ -12,9 +12,11 @@ import {BackToHomeComponent} from './back-to-home/back-to-home.component';
import {MatIconModule} from "@angular/material/icon";
import {StateManagementExampleComponent} from './state-management-example/state-management-example.component';
import {RestServicesModule} from "./core/rest-services/rest-services.module";
import {CarComponent} from './core/components/car/car.component';
import {ObservablesExampleModule} from "./observables-example/observables-example.module";
import {CoreModule} from "./core/core.module";
import {NetworkCallModule} from "./network-call/network-call.module";
import {HttpClientInMemoryWebApiModule} from "angular-in-memory-web-api";
import {RestApiMockService} from "./core/rest-api-mock/rest-api-mock.service";
@NgModule({
declarations: [
@@ -33,7 +35,14 @@ import {CoreModule} from "./core/core.module";
MatButtonModule,
MatIconModule,
RestServicesModule,
ObservablesExampleModule
ObservablesExampleModule,
NetworkCallModule,
HttpClientInMemoryWebApiModule.forRoot(
RestApiMockService,
{
dataEncapsulation: false
}
)
],
providers: [],
bootstrap: [AppComponent]

View File

@@ -3,7 +3,8 @@ import {CommonModule} from '@angular/common';
import {CarComponent} from "./components/car/car.component";
import {RestServicesModule} from "./rest-services/rest-services.module";
import {MaterialModule} from "./material.module";
import {HttpClientInMemoryWebApiModule} from "angular-in-memory-web-api";
import {RestApiMockService} from "./rest-api-mock/rest-api-mock.service";
@NgModule({
declarations: [
@@ -12,13 +13,13 @@ import {MaterialModule} from "./material.module";
imports: [
CommonModule,
RestServicesModule,
MaterialModule
MaterialModule,
],
exports: [
CarComponent,
RestServicesModule,
MaterialModule
]
],
})
export class CoreModule {
}

View File

@@ -2,11 +2,15 @@ import {NgModule} from "@angular/core";
import {MatIconModule} from "@angular/material/icon";
import {MatButtonModule} from "@angular/material/button";
import {MatTooltipModule} from "@angular/material/tooltip";
import {MatSnackBar, MatSnackBarModule} from "@angular/material/snack-bar";
import {MatProgressSpinnerModule} from "@angular/material/progress-spinner";
const IMPORTED_MATERIAL_MODULES = [
MatIconModule,
MatButtonModule,
MatTooltipModule
MatIconModule,
MatProgressSpinnerModule,
MatSnackBarModule,
MatTooltipModule,
]
@NgModule({

View File

@@ -1,5 +1,5 @@
export interface Car {
id: string;
id: number;
brand: string;
model: string;
power: number;

View File

@@ -0,0 +1,37 @@
import {Injectable} from '@angular/core';
import {InMemoryDbService} from "angular-in-memory-web-api";
import {Car} from "../model/car";
@Injectable({
providedIn: 'root'
})
export class RestApiMockService implements InMemoryDbService {
createDb() {
const cars: Car[] = [
{
id: 1,
brand: 'Toyota',
model: 'Yaris',
power: 12,
numberOfSeats: 5
},
{
id: 2,
brand: 'Citroën',
model: 'DS',
power: 14,
numberOfSeats: 5
},
{
id: 3,
brand: 'Renault',
model: 'Twingo',
power: 8,
numberOfSeats: 2
}
];
return {
cars
};
}
}

View File

@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Car} from "../model/car";
import {toPromise} from "../utils/promises.utils";
import {Observable} from "rxjs";
@Injectable({
providedIn: 'root'
@@ -12,7 +13,11 @@ export class CarRestService {
private http: HttpClient
) { }
findById(carId: string): Promise<Car> {
return toPromise(this.http.get<Car>(`/cars/${carId}`));
findById(carId: number): Promise<Car> {
return toPromise(this.findById$(carId));
}
findById$(carId: number): Observable<Car> {
return this.http.get<Car>(`/api/cars/${carId}`);
}
}

View File

@@ -8,6 +8,10 @@ export interface Link {
}
const LINKS: Link[] = [{
label: 'Les appels réseaux - Promesses ou Observables ?',
icon: '🌍',
href: '/network-call'
}, {
label: 'Les promesses',
icon: '🙏',
href: '/promises'

View File

@@ -0,0 +1,20 @@
<div class="component">
<h1>Les appels réseaux - Promesses ou Observables ?</h1>
<div class="actions">
<button mat-raised-button
(click)="loadCar()"
[disabled]="isLoading$ | async">
Load the car
</button>
</div>
<div class="loading" *ngIf="isLoading$ | async">
<h2>Loading...</h2>
<mat-spinner></mat-spinner>
</div>
<ng-container *ngIf="isLoaded">
<h2>Car data</h2>
<div class="centered">
<app-car [value]="car"></app-car>
</div>
</ng-container>
</div>

View File

@@ -0,0 +1,7 @@
.component {
.loading {
display: flex;
flex-direction: column;
align-items: center;
}
}

View File

@@ -0,0 +1,76 @@
import {Component} from '@angular/core';
import {BehaviorSubject, catchError, EMPTY, finalize, Observable, tap} from "rxjs";
import {Car} from "../core/model/car";
import {CarRestService} from "../core/rest-services/car.rest-service";
import {MatSnackBar} from "@angular/material/snack-bar";
const CAR_ID = 1;
@Component({
selector: 'app-network-call',
templateUrl: './network-call.component.html',
styleUrls: ['./network-call.component.scss']
})
export class NetworkCallComponent {
private isLoadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
isLoaded: boolean = false;
car?: Car;
constructor(
private carRestService: CarRestService,
private snackBar: MatSnackBar
) {
}
get isLoading$(): Observable<boolean> {
return this.isLoadingSubject.asObservable();
}
loadCar(): void {
this.loadThroughAPromise();
// this.loadThroughAnObservable();
}
private loadThroughAPromise(): void {
this.isLoadingSubject.next(true);
this.isLoaded = false;
this.carRestService.findById(CAR_ID)
.then(car => {
this.car = car;
this.isLoaded = true;
})
.catch(error => {
console.log('An error occured while loading the car.', error);
this.snackBar.open(
'An error occured while loading the car.',
'Close',
{duration: 2000}
);
})
.finally(() => this.isLoadingSubject.next(false));
}
private loadThroughAnObservable(): void {
this.isLoadingSubject.next(true);
this.isLoaded = false;
this.carRestService.findById$(CAR_ID)
.pipe(
tap(car => {
this.car = car;
this.isLoaded = true;
}),
catchError(error => {
console.log('An error occured while loading the car.', error);
this.snackBar.open(
'An error occured while loading the car.',
'Close',
{duration: 2000}
);
return EMPTY;
}),
finalize(() => this.isLoadingSubject.next(false))
).subscribe();
}
}

View File

@@ -0,0 +1,21 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {NetworkCallComponent} from "./network-call.component";
import {CoreModule} from "../core/core.module";
import {HttpClientModule} from "@angular/common/http";
@NgModule({
declarations: [
NetworkCallComponent
],
imports: [
CommonModule,
CoreModule,
HttpClientModule
],
exports: [
NetworkCallComponent
]
})
export class NetworkCallModule {
}

View File

@@ -6,5 +6,10 @@ import { Component } from '@angular/core';
styleUrls: ['./observables-example.component.scss']
})
export class ObservablesExampleComponent {
/*
Formulaires :
-> valueChanges / debounceTime etc...
Appel réseau -> pour voir la diff avec les promesses
*/
}

View File

@@ -17,7 +17,7 @@ export class SimpleObservableExempleComponent {
addNewCar(): void {
const newCar: Car = {
id: `${Math.random() * 100}`,
id: Math.random() * 100,
brand: 'Toyota',
model: 'Yaris',
power: 12,

View File

@@ -8,10 +8,17 @@ import {Car} from "../core/model/car";
})
export class PromisesExampleComponent {
car?: Car = {
id: '1234567890',
id: 1,
brand: 'Toyota',
model: 'Yaris',
power: 12,
numberOfSeats: 5
};
/*
// Async / Await -> + comparaison avec les then
// new Promise "à la main"
// les then chaînés
// catch (avec 1 ou plusieurs then) -> try/catch avec un await
*/
}

View File

@@ -2,3 +2,9 @@
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
.centered {
display: flex;
flex-direction: row;
justify-content: center;
}