Fin section 14 et 15 : programmation réactive et requêtes HTTP
This commit is contained in:
parent
a789a10203
commit
108c2b17a7
@ -25,6 +25,13 @@
|
|||||||
"@angular-devkit/build-angular": "^15.1.5",
|
"@angular-devkit/build-angular": "^15.1.5",
|
||||||
"@angular/cli": "~15.1.5",
|
"@angular/cli": "~15.1.5",
|
||||||
"@angular/compiler-cli": "^15.1.0",
|
"@angular/compiler-cli": "^15.1.0",
|
||||||
|
"angular-in-memory-web-api": "^0.15.0",
|
||||||
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"typescript": "~4.9.4"
|
"typescript": "~4.9.4"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"commitizen": {
|
||||||
|
"path": "./node_modules/cz-conventional-changelog"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,27 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
|
||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
|
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
|
||||||
import { PokemonModule } from './pokemon/pokemon.module';
|
import { PokemonModule } from './pokemon/pokemon.module';
|
||||||
|
import { InMemoryDataService } from './in-memory-data.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent, PageNotFoundComponent],
|
declarations: [AppComponent, PageNotFoundComponent],
|
||||||
imports: [BrowserModule, FormsModule, PokemonModule, AppRoutingModule],
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
FormsModule,
|
||||||
|
HttpClientModule,
|
||||||
|
HttpClientInMemoryWebApiModule.forRoot(InMemoryDataService, {
|
||||||
|
dataEncapsulation: false,
|
||||||
|
}),
|
||||||
|
PokemonModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
})
|
})
|
||||||
|
15
src/app/in-memory-data.service.ts
Normal file
15
src/app/in-memory-data.service.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { InMemoryDbService } from 'angular-in-memory-web-api';
|
||||||
|
import { POKEMONS } from './pokemon/mock-pokemon-list';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class InMemoryDataService implements InMemoryDbService {
|
||||||
|
createDb() {
|
||||||
|
const pokemons = POKEMONS;
|
||||||
|
return { pokemons };
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
}
|
2
src/app/pokemon/add-pokemon/add-pokemon.component.html
Normal file
2
src/app/pokemon/add-pokemon/add-pokemon.component.html
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<h2 class="center">Ajouter un pokémon</h2>
|
||||||
|
<app-pokemon-form [pokemon]="pokemon"></app-pokemon-form>
|
15
src/app/pokemon/add-pokemon/add-pokemon.component.ts
Normal file
15
src/app/pokemon/add-pokemon/add-pokemon.component.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Pokemon } from '../pokemon';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-pokemon',
|
||||||
|
templateUrl: './add-pokemon.component.html',
|
||||||
|
styles: [],
|
||||||
|
})
|
||||||
|
export class AddPokemonComponent implements OnInit {
|
||||||
|
pokemon: Pokemon;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.pokemon = new Pokemon();
|
||||||
|
}
|
||||||
|
}
|
@ -49,6 +49,7 @@
|
|||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<a (click)="goToPokemonList()">Retour</a>
|
<a (click)="goToPokemonList()">Retour</a>
|
||||||
<a (click)="goToEditPokemon(pokemon)">Modifier</a>
|
<a (click)="goToEditPokemon(pokemon)">Modifier</a>
|
||||||
|
<a (click)="deletePokemon(pokemon)">Supprimer</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,10 +19,18 @@ export class DetailPokemonComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
const pokemonId: string | null = this.route.snapshot.paramMap.get('id');
|
const pokemonId: string | null = this.route.snapshot.paramMap.get('id');
|
||||||
if (pokemonId) {
|
if (pokemonId) {
|
||||||
this.pokemon = this.pokemonService.getPokemonById(+pokemonId);
|
this.pokemonService
|
||||||
|
.getPokemonById(+pokemonId)
|
||||||
|
.subscribe((pokemon) => (this.pokemon = pokemon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deletePokemon(pokemon: Pokemon) {
|
||||||
|
this.pokemonService
|
||||||
|
.deletePokemonById(pokemon)
|
||||||
|
.subscribe(() => this.goToPokemonList());
|
||||||
|
}
|
||||||
|
|
||||||
goToPokemonList() {
|
goToPokemonList() {
|
||||||
this.router.navigate(['/pokemons']);
|
this.router.navigate(['/pokemons']);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,9 @@ export class EditPokemonComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const pokemonId: string | null = this.route.snapshot.paramMap.get('id');
|
const pokemonId: string | null = this.route.snapshot.paramMap.get('id');
|
||||||
if (pokemonId) {
|
if (pokemonId) {
|
||||||
this.pokemon = this.pokemonService.getPokemonById(+pokemonId);
|
this.pokemonService
|
||||||
|
.getPokemonById(+pokemonId)
|
||||||
|
.subscribe((pokemon) => (this.pokemon = pokemon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,3 +29,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<a
|
||||||
|
class="btn-floating btn-large waves-effect waves-ligth red z-depth-3"
|
||||||
|
style="position: fixed; bottom: 25px; right: 25px"
|
||||||
|
routerLink="/pokemon/add"
|
||||||
|
>➕</a
|
||||||
|
>
|
||||||
|
@ -13,7 +13,9 @@ export class ListPokemonComponent implements OnInit {
|
|||||||
constructor(private router: Router, private pokemonService: PokemonService) {}
|
constructor(private router: Router, private pokemonService: PokemonService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.pokemonList = this.pokemonService.getPokemonList();
|
this.pokemonService
|
||||||
|
.getPokemonList()
|
||||||
|
.subscribe((pokemonList) => (this.pokemonList = pokemonList));
|
||||||
}
|
}
|
||||||
|
|
||||||
goToPokemon(pokemon: Pokemon) {
|
goToPokemon(pokemon: Pokemon) {
|
||||||
|
@ -24,6 +24,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Pokemon picture -->
|
||||||
|
<div *ngIf="isAddForm" class="form-group">
|
||||||
|
<label for="name">Image</label>
|
||||||
|
<input
|
||||||
|
type="url"
|
||||||
|
class="form-control"
|
||||||
|
id="picture"
|
||||||
|
required
|
||||||
|
[(ngModel)]="pokemon.picture"
|
||||||
|
name="picture"
|
||||||
|
#picture="ngModel"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
[hidden]="picture.valid || picture.pristine"
|
||||||
|
class="card-panel red accent-1"
|
||||||
|
>
|
||||||
|
L’image du pokémon est requise.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Pokemon hp -->
|
<!-- Pokemon hp -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="hp">Point de vie</label>
|
<label for="hp">Point de vie</label>
|
||||||
|
@ -11,11 +11,15 @@ import { PokemonService } from '../pokemon.service';
|
|||||||
export class PokemonFormComponent implements OnInit {
|
export class PokemonFormComponent implements OnInit {
|
||||||
@Input() pokemon: Pokemon;
|
@Input() pokemon: Pokemon;
|
||||||
types: string[];
|
types: string[];
|
||||||
|
isAddForm: boolean;
|
||||||
|
|
||||||
constructor(private pokemonService: PokemonService, private router: Router) {}
|
constructor(private pokemonService: PokemonService, private router: Router) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.types = this.pokemonService.getPokemonTypeList();
|
this.pokemonService
|
||||||
|
.getPokemonTypeList()
|
||||||
|
.subscribe((types) => (this.types = types));
|
||||||
|
this.isAddForm = this.router.url.includes('add');
|
||||||
}
|
}
|
||||||
|
|
||||||
hasType(type: string) {
|
hasType(type: string) {
|
||||||
@ -33,8 +37,17 @@ export class PokemonFormComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
console.log('Submit form!');
|
if (this.isAddForm) {
|
||||||
this.router.navigate(['/pokemon', this.pokemon.id]);
|
this.pokemonService
|
||||||
|
.addPokemon(this.pokemon)
|
||||||
|
.subscribe((pokemon: Pokemon) => {
|
||||||
|
this.router.navigate(['/pokemon', pokemon.id]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.pokemonService.updatePokemon(this.pokemon).subscribe(() => {
|
||||||
|
this.router.navigate(['/pokemon', this.pokemon.id]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isTypesValid(type: string): boolean {
|
isTypesValid(type: string): boolean {
|
||||||
|
@ -10,9 +10,11 @@ import { PokemonService } from './pokemon.service';
|
|||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { PokemonFormComponent } from './pokemon-form/pokemon-form.component';
|
import { PokemonFormComponent } from './pokemon-form/pokemon-form.component';
|
||||||
import { EditPokemonComponent } from './edit-pokemon/edit-pokemon.component';
|
import { EditPokemonComponent } from './edit-pokemon/edit-pokemon.component';
|
||||||
|
import { AddPokemonComponent } from './add-pokemon/add-pokemon.component';
|
||||||
|
|
||||||
const pokemonRoutes: Routes = [
|
const pokemonRoutes: Routes = [
|
||||||
{ path: 'edit/pokemon/:id', component: EditPokemonComponent },
|
{ path: 'edit/pokemon/:id', component: EditPokemonComponent },
|
||||||
|
{ path: 'pokemon/add', component: AddPokemonComponent },
|
||||||
{ path: 'pokemon/:id', component: DetailPokemonComponent },
|
{ path: 'pokemon/:id', component: DetailPokemonComponent },
|
||||||
{ path: 'pokemons', component: ListPokemonComponent },
|
{ path: 'pokemons', component: ListPokemonComponent },
|
||||||
];
|
];
|
||||||
@ -25,6 +27,7 @@ const pokemonRoutes: Routes = [
|
|||||||
DetailPokemonComponent,
|
DetailPokemonComponent,
|
||||||
PokemonFormComponent,
|
PokemonFormComponent,
|
||||||
EditPokemonComponent,
|
EditPokemonComponent,
|
||||||
|
AddPokemonComponent,
|
||||||
],
|
],
|
||||||
imports: [CommonModule, FormsModule, RouterModule.forChild(pokemonRoutes)],
|
imports: [CommonModule, FormsModule, RouterModule.forChild(pokemonRoutes)],
|
||||||
providers: [PokemonService],
|
providers: [PokemonService],
|
||||||
|
@ -1,22 +1,74 @@
|
|||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { POKEMONS } from './mock-pokemon-list';
|
import { catchError, mergeMap, Observable, of, tap } from 'rxjs';
|
||||||
import { Pokemon } from './pokemon';
|
import { Pokemon } from './pokemon';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PokemonService {
|
export class PokemonService {
|
||||||
getPokemonList(): Pokemon[] {
|
constructor(private http: HttpClient) {}
|
||||||
return POKEMONS;
|
|
||||||
|
getPokemonList(): Observable<Pokemon[]> {
|
||||||
|
return this.http.get<Pokemon[]>('api/pokemons').pipe(
|
||||||
|
tap((pokemonList) => this.log(pokemonList)),
|
||||||
|
catchError((error) => this.handleError(error, []))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPokemonById(pokemonId: number): Pokemon | undefined {
|
getPokemonById(pokemonId: number): Observable<Pokemon | undefined> {
|
||||||
return POKEMONS.find((pokemon) => pokemon.id === pokemonId);
|
return this.http.get<Pokemon>(`api/pokemons/${pokemonId}`).pipe(
|
||||||
|
tap((pokemon) => this.log(pokemon)),
|
||||||
|
catchError((error) => this.handleError(error, undefined))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPokemonTypeList(): string[] {
|
getPokemonTypeList(): Observable<string[]> {
|
||||||
const types: Set<string> = new Set();
|
return this.http.get<Pokemon[]>('api/pokemons').pipe(
|
||||||
POKEMONS.forEach((pokemon) => {
|
mergeMap((pokemons: Pokemon[]) => {
|
||||||
pokemon.types.forEach((type) => types.add(type));
|
const set = new Set<string>();
|
||||||
});
|
pokemons.forEach((pokemon) =>
|
||||||
return Array.from(types.values());
|
pokemon.types.forEach((type) => set.add(type))
|
||||||
|
);
|
||||||
|
return [Array.from(set.values())];
|
||||||
|
}),
|
||||||
|
tap((pokemon) => this.log(pokemon)),
|
||||||
|
catchError((error) => this.handleError(error, []))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePokemon(pokemon: Pokemon): Observable<null> {
|
||||||
|
const httpOptions = {
|
||||||
|
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
|
||||||
|
};
|
||||||
|
return this.http.put('api/pokemons', pokemon, httpOptions).pipe(
|
||||||
|
tap((response) => this.log(response)),
|
||||||
|
catchError((error) => this.handleError(error, null))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPokemon(pokemon: Pokemon): Observable<Pokemon> {
|
||||||
|
const httpOptions = {
|
||||||
|
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.post<Pokemon>('api/pokemons', pokemon, httpOptions).pipe(
|
||||||
|
tap((response) => this.log(response)),
|
||||||
|
catchError((error) => this.handleError(error, null))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
deletePokemonById(pokemon: Pokemon): Observable<null> {
|
||||||
|
return this.http.delete(`api/pokemons/${pokemon.id}`).pipe(
|
||||||
|
tap((response) => this.log(response)),
|
||||||
|
catchError((error) => this.handleError(error, null))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private log(response: any) {
|
||||||
|
console.table(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleError(error: Error, errorValue: any) {
|
||||||
|
console.error(error);
|
||||||
|
return of(errorValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
export class Pokemon {
|
export class Pokemon {
|
||||||
id: number;
|
id: number;
|
||||||
|
name: string;
|
||||||
hp: number;
|
hp: number;
|
||||||
cp: number;
|
cp: number;
|
||||||
name: string;
|
|
||||||
picture: string;
|
picture: string;
|
||||||
types: Array<string>;
|
types: Array<string>;
|
||||||
created: Date;
|
created: Date;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
name: string = 'Enter a name...',
|
||||||
|
hp: number = 100,
|
||||||
|
cp: number = 10,
|
||||||
|
picture: string = 'https://assets.pokemon.com/assets/cms2/img/pokedex/detail/xxx.png',
|
||||||
|
types: string[] = ['Normal'],
|
||||||
|
created: Date = new Date()
|
||||||
|
) {
|
||||||
|
this.hp = hp;
|
||||||
|
this.cp = cp;
|
||||||
|
this.name = name;
|
||||||
|
this.picture = picture;
|
||||||
|
this.types = types;
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user