Skip to content

Commit

Permalink
v1.1.0: Messages with Alert
Browse files Browse the repository at this point in the history
  • Loading branch information
peimelo committed Jul 17, 2020
1 parent f35cda1 commit 78e15b0
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 39 deletions.
11 changes: 11 additions & 0 deletions src/app/alert.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export enum AlertType {
success = 'success',
info = 'info',
warning = 'warning',
danger = 'danger',
}

export interface Alert {
type: AlertType;
message: string;
}
5 changes: 3 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
import { NgbAlertModule, NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { environment } from 'src/environments/environment';
import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { DashboardComponent } from './dashboard/dashboard.component';
Expand Down Expand Up @@ -36,6 +36,7 @@ import { SearchInputComponent } from './search-input/search-input.component';
FormsModule,
AppRoutingModule,
NgbCollapseModule,
NgbAlertModule,
HttpClientModule,
environment.production
? []
Expand Down
68 changes: 41 additions & 27 deletions src/app/hero.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { environment } from '../environments/environment';
import { environment } from 'src/environments/environment';
import { AlertType } from './alert.model';
import { Hero } from './hero.model';
import { MessageService } from './message.service';

Expand All @@ -20,79 +21,92 @@ export class HeroService {
};

constructor(
private http: HttpClient,
private messageService: MessageService
private messageService: MessageService,
private http: HttpClient
) {}

// GET /heroes
getHeroes(): Observable<Hero[]> {
return this.http.get<Hero[]>(this.heroesUrl, this.httpOptions).pipe(
tap(() => this.log('fetched heroes')),
tap((heroes) => {
this.log(`fetched ${heroes.length} heroes`);
}),
catchError(this.handleError<Hero[]>('getHeroes', []))
);
}

// GET /heroes/id
getHero(id: number): Observable<Hero> {
const url = `${this.heroesUrl}/${id}`;

return this.http.get<Hero>(url, this.httpOptions).pipe(
tap(() => this.log(`fetched hero id=${id}`)),
catchError(this.handleError<Hero>('getHeroes'))
);
return this.http
.get<Hero>(`${this.heroesUrl}/${id}`, this.httpOptions)
.pipe(
tap(() => this.log(`fetched hero id=${id}.`)),
catchError(this.handleError<Hero>('getHero'))
);
}

// PUT /heroes/id
updateHero(hero: Hero): Observable<Hero> {
const url = `${this.heroesUrl}/${hero.id}`;

return this.http.put<Hero>(url, hero, this.httpOptions).pipe(
tap(() => this.log(`updated hero id=${hero.id}`)),
catchError(this.handleError<Hero>('updateHeroes'))
tap(() => this.log(`updated hero id=${hero.id}.`, AlertType.success)),
catchError(this.handleError<Hero>('updateHero'))
);
}

// POST /heroes
addHero(hero: Hero): Observable<Hero> {
return this.http.post(this.heroesUrl, hero, this.httpOptions).pipe(
tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
return this.http.post<Hero>(this.heroesUrl, hero, this.httpOptions).pipe(
tap((newHero) =>
this.log(`added hero w/ id=${newHero.id}.`, AlertType.success)
),
catchError(this.handleError<Hero>('addHero'))
);
}

// DELETE /heroes/id
deleteHero(hero: Hero): Observable<any> {
const url = `${this.heroesUrl}/${hero.id}`;

return this.http.delete<any>(url, this.httpOptions).pipe(
tap(() => this.log(`deleted hero id=${hero.id}`)),
return this.http.delete<Hero>(url, this.httpOptions).pipe(
tap(() => this.log(`deleted hero id=${hero.id}.`, AlertType.success)),
catchError(this.handleError<Hero>('deleteHero'))
);
}

// GET /heroes/?name=term
searchHeroes(term: string): Observable<Hero[]> {
if (!term.trim()) {
if (!(term && term.trim())) {
return of([]);
}

return this.http
.get<Hero[]>(`${this.heroesUrl}/?name=${term}`, this.httpOptions)
.pipe(
tap((heroes) =>
tap((heroes) => {
heroes && heroes.length
? this.log(`found heroes matching "${term}"`)
: this.log(`no heroes matching "${term}"`)
),
? this.log(`found ${heroes.length} heroes matching term=${term}`)
: this.log(`no heroes matching term=${term}`, AlertType.warning);
}),
catchError(this.handleError<Hero[]>('searchHeroes', []))
);
}

private log(message: string, type = AlertType.info) {
this.messageService.add({
message: `HeroService: ${message}`,
type,
});
}

private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.log(error);

this.log(`${operation} failed: ${error.message}`);
this.log(`${operation} failed: ${error.message}`, AlertType.danger);

return of(result as T);
return of(result);
};
}

private log(message: string) {
this.messageService.add(`HeroService: ${message}`);
}
}
5 changes: 4 additions & 1 deletion src/app/heroes/heroes.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ <h2>My Heroes</h2>
</div>

<div class="col-12 col-sm-6">
<app-search-input (search)="onFilter($event)"></app-search-input>
<app-search-input
[label]="'Filter'"
(search)="onFilter($event)"
></app-search-input>
</div>
</div>

Expand Down
17 changes: 13 additions & 4 deletions src/app/message.service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import { Injectable } from '@angular/core';
import { Alert } from './alert.model';

@Injectable({
providedIn: 'root',
})
export class MessageService {
messages: string[] = [];
private alerts: Alert[] = [];

add(message: string) {
this.messages.push(message);
getMessages(): Alert[] {
return this.alerts;
}

add(alert: Alert) {
this.alerts.push(alert);
}

clear() {
this.messages = [];
this.alerts = [];
}

close(alert: Alert) {
this.alerts.splice(this.alerts.indexOf(alert), 1);
}
}
10 changes: 5 additions & 5 deletions src/app/messages/messages.component.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div *ngIf="messageService.messages.length">
<div *ngIf="messageService.getMessages().length">
<h2>Messages</h2>

<button
Expand All @@ -9,9 +9,9 @@ <h2>Messages</h2>
Clear
</button>

<div *ngFor="let message of messageService.messages">
<div class="alert alert-success" role="alert">
{{ message }}
</div>
<div *ngFor="let alert of messageService.getMessages()">
<ngb-alert [type]="alert.type" (close)="close(alert)">
{{ alert.message }}
</ngb-alert>
</div>
</div>
5 changes: 5 additions & 0 deletions src/app/messages/messages.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component } from '@angular/core';
import { Alert } from '../alert.model';
import { MessageService } from '../message.service';

@Component({
Expand All @@ -8,4 +9,8 @@ import { MessageService } from '../message.service';
})
export class MessagesComponent {
constructor(public messageService: MessageService) {}

close(alert: Alert) {
this.messageService.close(alert);
}
}

0 comments on commit 78e15b0

Please sign in to comment.