From 1e585195e9a68514266d251b4f8bf1464918cc18 Mon Sep 17 00:00:00 2001 From: "DESKTOP-8HAFCLV\\Yugr" Date: Tue, 24 Jun 2025 10:11:52 +0400 Subject: [PATCH 1/3] fixed in-memory-data --- package-lock.json | 15 +++++++++++++++ package.json | 1 + src/app/app.config.ts | 8 ++++++-- src/app/hero.service.ts | 27 ++++++++++++++++++++------ src/app/in-memory-data.service.ts | 32 +++++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 src/app/in-memory-data.service.ts diff --git a/package-lock.json b/package-lock.json index f542efa..8263844 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@angular/forms": "^20.0.0", "@angular/platform-browser": "^20.0.0", "@angular/router": "^20.0.0", + "angular-in-memory-web-api": "^0.20.0", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, @@ -3378,6 +3379,20 @@ } } }, + "node_modules/angular-in-memory-web-api": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/angular-in-memory-web-api/-/angular-in-memory-web-api-0.20.0.tgz", + "integrity": "sha512-piEcu1MvHOnPnESSFgzHEz9YUDxqQ1WbH8yp9f0sXr+//dTEEj/pY6YY7OthBSUP/DLTAEE4itE1SOYs0dOKMA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^20.0.0", + "@angular/core": "^20.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", diff --git a/package.json b/package.json index a438fa1..93774a8 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@angular/forms": "^20.0.0", "@angular/platform-browser": "^20.0.0", "@angular/router": "^20.0.0", + "angular-in-memory-web-api": "^0.20.0", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 2e06ce8..237f81b 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,10 +1,14 @@ -import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core'; +import { ApplicationConfig, importProvidersFrom, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; - +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; import { routes } from './app.routes'; +import { provideHttpClient } from '@angular/common/http'; +import { InMemoryDataService } from './in-memory-data.service'; export const appConfig: ApplicationConfig = { providers: [ + provideHttpClient(), + importProvidersFrom(InMemoryWebApiModule.forRoot(InMemoryDataService, { delay: 150 })), provideBrowserGlobalErrorListeners(), provideZonelessChangeDetection(), provideRouter(routes) diff --git a/src/app/hero.service.ts b/src/app/hero.service.ts index 488a84e..a419ff4 100644 --- a/src/app/hero.service.ts +++ b/src/app/hero.service.ts @@ -3,6 +3,7 @@ import { Hero } from './hero'; import { HEROES } from './mock-heroes'; import { Observable, of } from 'rxjs'; import { MessageService } from './message.service'; +import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' @@ -10,13 +11,23 @@ import { MessageService } from './message.service'; export class HeroService { - constructor(private messageService: MessageService) { } + private heroesUrl = 'api/heroes'; // URL to web api -getHeroes(): Observable { - const heroes = of(HEROES); - this.messageService.add('HeroService: fetched heroes'); - return heroes; -} + constructor( + private http: HttpClient, + private messageService: MessageService) + { } + + // getHeroes(): Observable { + // const heroes = of(HEROES); + // this.messageService.add('HeroService: fetched heroes'); + // return heroes; + // } + + /** GET heroes from the server */ + getHeroes(): Observable { + return this.http.get(this.heroesUrl) + } getHero(id: number): Observable { // For now, assume that a hero with the specified `id` always exists. @@ -26,4 +37,8 @@ getHeroes(): Observable { return of(hero); } + /** Log a HeroService message with the MessageService */ + private log(message: string) { + this.messageService.add(`HeroService: ${message}`); + } } \ No newline at end of file diff --git a/src/app/in-memory-data.service.ts b/src/app/in-memory-data.service.ts new file mode 100644 index 0000000..d338236 --- /dev/null +++ b/src/app/in-memory-data.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; +import { InMemoryDbService } from 'angular-in-memory-web-api'; +import { Hero } from './hero'; + +@Injectable({ + providedIn: 'root', +}) +export class InMemoryDataService implements InMemoryDbService { + createDb() { + const heroes = [ + { id: 12, name: 'Dr. Nice' }, + { id: 13, name: 'Bombasto' }, + { id: 14, name: 'Celeritas' }, + { id: 15, name: 'Magneta' }, + { id: 16, name: 'RubberMan' }, + { id: 17, name: 'Dynama' }, + { id: 18, name: 'Dr. IQ' }, + { id: 19, name: 'Magma' }, + { id: 20, name: 'Tornado' } + ]; + return {heroes}; + } + + // Overrides the genId method to ensure that a hero always has an id. + // If the heroes array is empty, + // the method below returns the initial number (11). + // if the heroes array is not empty, the method below returns the highest + // hero id + 1. + genId(heroes: Hero[]): number { + return heroes.length > 0 ? Math.max(...heroes.map(hero => hero.id)) + 1 : 11; + } +} \ No newline at end of file From 033b12ef11385cfc341ac92a8cce6d0029688143 Mon Sep 17 00:00:00 2001 From: "DESKTOP-P9VU163\\admin" Date: Tue, 24 Jun 2025 09:21:53 +0300 Subject: [PATCH 2/3] add less 6 handleError --- src/app/hero.service.ts | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/app/hero.service.ts b/src/app/hero.service.ts index a419ff4..5462f55 100644 --- a/src/app/hero.service.ts +++ b/src/app/hero.service.ts @@ -4,6 +4,7 @@ import { HEROES } from './mock-heroes'; import { Observable, of } from 'rxjs'; import { MessageService } from './message.service'; import { HttpClient } from '@angular/common/http'; +import { catchError, map, tap } from 'rxjs/operators'; @Injectable({ providedIn: 'root' @@ -18,15 +19,11 @@ export class HeroService { private messageService: MessageService) { } - // getHeroes(): Observable { - // const heroes = of(HEROES); - // this.messageService.add('HeroService: fetched heroes'); - // return heroes; - // } - - /** GET heroes from the server */ getHeroes(): Observable { - return this.http.get(this.heroesUrl) + return this.http.get(this.heroesUrl) + .pipe( + catchError(this.handleError('getHeroes', [])) + ); } getHero(id: number): Observable { @@ -37,8 +34,31 @@ export class HeroService { return of(hero); } + /** + * Handle Http operation that failed. + * Let the app continue. + * + * @param operation - name of the operation that failed + * @param result - optional value to return as the observable result + */ + private handleError(operation = 'operation', result?: T) { + return (error: any): Observable => { + + // TODO: send the error to remote logging infrastructure + console.error(error); // log to console instead + + // TODO: better job of transforming error for user consumption + this.log(`${operation} failed: ${error.message}`); + + // Let the app keep running by returning an empty result. + return of(result as T); + }; + } + /** Log a HeroService message with the MessageService */ private log(message: string) { this.messageService.add(`HeroService: ${message}`); } + + } \ No newline at end of file From b8d35150a431b2cbfd06185dd5f307f08d4c773e Mon Sep 17 00:00:00 2001 From: "DESKTOP-P9VU163\\admin" Date: Tue, 24 Jun 2025 09:45:41 +0300 Subject: [PATCH 3/3] add less 6 herro update --- .../hero-detail/hero-detail.component.html | 7 ++-- src/app/hero-detail/hero-detail.component.ts | 7 ++++ src/app/hero.service.ts | 35 +++++++++++++------ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/app/hero-detail/hero-detail.component.html b/src/app/hero-detail/hero-detail.component.html index d780243..023e31c 100644 --- a/src/app/hero-detail/hero-detail.component.html +++ b/src/app/hero-detail/hero-detail.component.html @@ -1,12 +1,11 @@
- - -

{{hero.name | uppercase}} Details

id: {{hero.id}}
-
+ + + diff --git a/src/app/hero-detail/hero-detail.component.ts b/src/app/hero-detail/hero-detail.component.ts index 78342f4..8713c2f 100644 --- a/src/app/hero-detail/hero-detail.component.ts +++ b/src/app/hero-detail/hero-detail.component.ts @@ -39,4 +39,11 @@ export class HeroDetailComponent { .subscribe(hero => this.hero = hero); } + save(): void { + if (this.hero) { + this.heroService.updateHero(this.hero) + .subscribe(() => this.goBack()); + } + } + } diff --git a/src/app/hero.service.ts b/src/app/hero.service.ts index 5462f55..5432051 100644 --- a/src/app/hero.service.ts +++ b/src/app/hero.service.ts @@ -3,7 +3,7 @@ import { Hero } from './hero'; import { HEROES } from './mock-heroes'; import { Observable, of } from 'rxjs'; import { MessageService } from './message.service'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { catchError, map, tap } from 'rxjs/operators'; @Injectable({ @@ -13,25 +13,40 @@ import { catchError, map, tap } from 'rxjs/operators'; export class HeroService { private heroesUrl = 'api/heroes'; // URL to web api + + httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }) + }; constructor( private http: HttpClient, private messageService: MessageService) { } + /** GET heroes from the server */ getHeroes(): Observable { - return this.http.get(this.heroesUrl) - .pipe( - catchError(this.handleError('getHeroes', [])) + return this.http.get(this.heroesUrl) + .pipe( + tap(_ => this.log('fetched heroes')), + catchError(this.handleError('getHeroes', [])) + ); + } + + /** GET hero by id. Will 404 if id not found */ + getHero(id: number): Observable { + const url = `${this.heroesUrl}/${id}`; + return this.http.get(url).pipe( + tap(_ => this.log(`fetched hero id=${id}`)), + catchError(this.handleError(`getHero id=${id}`)) ); } - getHero(id: number): Observable { - // For now, assume that a hero with the specified `id` always exists. - // Error handling will be added in the next step of the tutorial. - const hero = HEROES.find(h => h.id === id)!; - this.messageService.add(`HeroService: fetched hero id=${id}`); - return of(hero); + /** PUT: update the hero on the server */ + updateHero(hero: Hero): Observable { + return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe( + tap(_ => this.log(`updated hero id=${hero.id}`)), + catchError(this.handleError('updateHero')) + ); } /**