From cfd4838d1744bf4a45cc97d7b2cf3f8fe8e107d9 Mon Sep 17 00:00:00 2001 From: Florian THIERRY Date: Tue, 21 Feb 2023 15:25:03 +0100 Subject: [PATCH] Ajout d'un exemple pour les appels http. --- package-lock.json | 22 ++++++ package.json | 3 +- src/app/app-routing.module.ts | 5 ++ src/app/app.module.ts | 13 +++- src/app/core/core.module.ts | 7 +- src/app/core/material.module.ts | 8 +- src/app/core/model/car.ts | 2 +- .../rest-api-mock/rest-api-mock.service.ts | 37 +++++++++ .../core/rest-services/car.rest-service.ts | 9 ++- src/app/home/home.component.ts | 4 + .../network-call/network-call.component.html | 20 +++++ .../network-call/network-call.component.scss | 7 ++ .../network-call/network-call.component.ts | 76 +++++++++++++++++++ src/app/network-call/network-call.module.ts | 21 +++++ .../observables-example.component.ts | 5 ++ .../simple-observable-exemple.component.ts | 2 +- .../promises-example.component.ts | 9 ++- src/styles.scss | 6 ++ 18 files changed, 243 insertions(+), 13 deletions(-) create mode 100644 src/app/core/rest-api-mock/rest-api-mock.service.ts create mode 100644 src/app/network-call/network-call.component.html create mode 100644 src/app/network-call/network-call.component.scss create mode 100644 src/app/network-call/network-call.component.ts create mode 100644 src/app/network-call/network-call.module.ts diff --git a/package-lock.json b/package-lock.json index 7df00f4..66e8daf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@angular/platform-browser": "^15.1.0", "@angular/platform-browser-dynamic": "^15.1.0", "@angular/router": "^15.1.0", + "angular-in-memory-web-api": "^0.15.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.12.0" @@ -4382,6 +4383,19 @@ "ajv": "^8.8.2" } }, + "node_modules/angular-in-memory-web-api": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/angular-in-memory-web-api/-/angular-in-memory-web-api-0.15.0.tgz", + "integrity": "sha512-T07vQTeBEGWfwZRM+jIooYgK4c8LR25I27otIthUkFINAREoPiBNogWDxlnROIeu1k2RrY3QJjMOYq7f62UcgA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^15.0.0", + "@angular/core": "^15.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -15346,6 +15360,14 @@ "fast-deep-equal": "^3.1.3" } }, + "angular-in-memory-web-api": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/angular-in-memory-web-api/-/angular-in-memory-web-api-0.15.0.tgz", + "integrity": "sha512-T07vQTeBEGWfwZRM+jIooYgK4c8LR25I27otIthUkFINAREoPiBNogWDxlnROIeu1k2RrY3QJjMOYq7f62UcgA==", + "requires": { + "tslib": "^2.3.0" + } + }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", diff --git a/package.json b/package.json index 6390dff..7a4de1a 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@angular/platform-browser": "^15.1.0", "@angular/platform-browser-dynamic": "^15.1.0", "@angular/router": "^15.1.0", + "angular-in-memory-web-api": "^0.15.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.12.0" @@ -37,4 +38,4 @@ "karma-jasmine-html-reporter": "~2.0.0", "typescript": "~4.9.4" } -} \ No newline at end of file +} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 6c76b16..587e516 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -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 diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 02bceb2..6b5ef79 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -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] diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index a603080..583ae9f 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -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 { } diff --git a/src/app/core/material.module.ts b/src/app/core/material.module.ts index 6ad7bd0..d5dc3e4 100644 --- a/src/app/core/material.module.ts +++ b/src/app/core/material.module.ts @@ -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({ diff --git a/src/app/core/model/car.ts b/src/app/core/model/car.ts index 1faa5cb..8dc5a35 100644 --- a/src/app/core/model/car.ts +++ b/src/app/core/model/car.ts @@ -1,5 +1,5 @@ export interface Car { - id: string; + id: number; brand: string; model: string; power: number; diff --git a/src/app/core/rest-api-mock/rest-api-mock.service.ts b/src/app/core/rest-api-mock/rest-api-mock.service.ts new file mode 100644 index 0000000..66193a1 --- /dev/null +++ b/src/app/core/rest-api-mock/rest-api-mock.service.ts @@ -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 + }; + } +} diff --git a/src/app/core/rest-services/car.rest-service.ts b/src/app/core/rest-services/car.rest-service.ts index 0cd0897..3ea75c2 100644 --- a/src/app/core/rest-services/car.rest-service.ts +++ b/src/app/core/rest-services/car.rest-service.ts @@ -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 { - return toPromise(this.http.get(`/cars/${carId}`)); + findById(carId: number): Promise { + return toPromise(this.findById$(carId)); + } + + findById$(carId: number): Observable { + return this.http.get(`/api/cars/${carId}`); } } diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index ba620ea..16d287e 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -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' diff --git a/src/app/network-call/network-call.component.html b/src/app/network-call/network-call.component.html new file mode 100644 index 0000000..96c36ef --- /dev/null +++ b/src/app/network-call/network-call.component.html @@ -0,0 +1,20 @@ +
+

Les appels réseaux - Promesses ou Observables ?

+
+ +
+
+

Loading...

+ +
+ +

Car data

+
+ +
+
+
\ No newline at end of file diff --git a/src/app/network-call/network-call.component.scss b/src/app/network-call/network-call.component.scss new file mode 100644 index 0000000..5ed7c06 --- /dev/null +++ b/src/app/network-call/network-call.component.scss @@ -0,0 +1,7 @@ +.component { + .loading { + display: flex; + flex-direction: column; + align-items: center; + } +} \ No newline at end of file diff --git a/src/app/network-call/network-call.component.ts b/src/app/network-call/network-call.component.ts new file mode 100644 index 0000000..ca7f1db --- /dev/null +++ b/src/app/network-call/network-call.component.ts @@ -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 = new BehaviorSubject(false); + isLoaded: boolean = false; + car?: Car; + + constructor( + private carRestService: CarRestService, + private snackBar: MatSnackBar + ) { + } + + get isLoading$(): Observable { + 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(); + } +} diff --git a/src/app/network-call/network-call.module.ts b/src/app/network-call/network-call.module.ts new file mode 100644 index 0000000..3859ddd --- /dev/null +++ b/src/app/network-call/network-call.module.ts @@ -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 { +} diff --git a/src/app/observables-example/observables-example.component.ts b/src/app/observables-example/observables-example.component.ts index 63c92c9..f09cd5c 100644 --- a/src/app/observables-example/observables-example.component.ts +++ b/src/app/observables-example/observables-example.component.ts @@ -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 + */ } diff --git a/src/app/observables-example/simple-observable-exemple/simple-observable-exemple.component.ts b/src/app/observables-example/simple-observable-exemple/simple-observable-exemple.component.ts index 456282f..2f04504 100644 --- a/src/app/observables-example/simple-observable-exemple/simple-observable-exemple.component.ts +++ b/src/app/observables-example/simple-observable-exemple/simple-observable-exemple.component.ts @@ -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, diff --git a/src/app/promises-example/promises-example.component.ts b/src/app/promises-example/promises-example.component.ts index fdc78b7..3be38c2 100644 --- a/src/app/promises-example/promises-example.component.ts +++ b/src/app/promises-example/promises-example.component.ts @@ -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 + */ } diff --git a/src/styles.scss b/src/styles.scss index 7e7239a..63ea5c4 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -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; +} \ No newline at end of file