Skip to content

Commit 0c4c685

Browse files
IsmaestroIsmael Ramos
authored andcommitted
feat(interceptors): added two interceptors example and refactor progress bar service
1 parent b73f13a commit 0c4c685

File tree

8 files changed

+75
-39
lines changed

8 files changed

+75
-39
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Live DEMO [here](http://angularexampleapp.com/)!
6161
* Responsive layout (flex layout module)
6262
* Internationalization
6363
* Lazy loading modules
64-
* Progress bar active, if a request is pending (events)
64+
* Interceptors and Events (Progress bar active, if a request is pending)
6565
* CRUD: create, update and remove heroes
6666
* Search bar, to look for heroes
6767
* Modal and toasts (snakbar)!

src/app/app.module.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ import {CoreModule} from './core/core.module';
1010

1111
import {AppComponent} from './app.component';
1212
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
13-
import {HttpClient, HttpClientModule} from '@angular/common/http';
13+
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from '@angular/common/http';
1414
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
1515
import {HttpLoaderFactory} from './app.translate.factory';
1616
import {HeroTopComponent} from './heroes/hero-top/hero-top.component';
17+
import {ProgressBarService} from './core/progress-bar.service';
18+
import {ProgressInterceptor} from './shared/interceptors/progress.interceptor';
19+
import {TimingInterceptor} from './shared/interceptors/timing.interceptor';
1720

1821
@NgModule({
1922
imports: [
@@ -37,7 +40,9 @@ import {HeroTopComponent} from './heroes/hero-top/hero-top.component';
3740
HeroTopComponent
3841
],
3942
providers: [
40-
{provide: APP_CONFIG, useValue: AppConfig}
43+
{provide: APP_CONFIG, useValue: AppConfig},
44+
{provide: HTTP_INTERCEPTORS, useClass: ProgressInterceptor, multi: true, deps: [ProgressBarService]},
45+
{provide: HTTP_INTERCEPTORS, useClass: TimingInterceptor, multi: true}
4146
],
4247
bootstrap: [AppComponent]
4348
})

src/app/core/progress-bar.service.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('ProgressBarService', () => {
2727
});
2828

2929
it('should not be requestsRunning', (() => {
30-
const instance = new ProgressBarService(heroService);
30+
const instance = new ProgressBarService();
3131
expect(instance).toBeTruthy();
3232
}));
3333

@@ -36,14 +36,14 @@ describe('ProgressBarService', () => {
3636
}));
3737

3838
it('should increase and decrease the counter of requests running', (() => {
39-
heroService.request$.emit('starting');
40-
heroService.request$.emit('starting');
39+
progressBarService.increase();
40+
progressBarService.increase();
4141
expect(progressBarService.requestsRunning).toBe(2);
42-
heroService.request$.emit('finished');
42+
progressBarService.decrease();
4343
expect(progressBarService.requestsRunning).toBe(1);
44-
heroService.request$.emit('finished');
44+
progressBarService.decrease();
4545
expect(progressBarService.requestsRunning).toBe(0);
46-
heroService.request$.emit('finished');
46+
progressBarService.decrease();
4747
expect(progressBarService.requestsRunning).toBe(0);
4848
}));
4949
});
Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
import {EventEmitter, Injectable} from '@angular/core';
2-
import {HeroService} from '../heroes/shared/hero.service';
32

43
@Injectable()
54
export class ProgressBarService {
65
public updateProgressBar$: EventEmitter<any>;
76

87
private requestsRunning = 0;
98

10-
constructor(private heroService: HeroService) {
9+
constructor() {
1110
this.updateProgressBar$ = new EventEmitter();
11+
}
12+
13+
public list(): number {
14+
return this.requestsRunning;
15+
}
16+
17+
public increase(): void {
18+
this.requestsRunning++;
19+
if (this.requestsRunning === 1) {
20+
this.updateProgressBar$.emit('query');
21+
}
22+
}
1223

13-
this.heroService.request$.subscribe((type: string) => {
14-
if (type === 'starting') {
15-
this.requestsRunning++;
16-
if (this.requestsRunning === 1) {
17-
this.updateProgressBar$.emit('query');
18-
}
19-
} else if (this.requestsRunning > 0) {
20-
this.requestsRunning--;
21-
if (this.requestsRunning === 0) {
22-
this.updateProgressBar$.emit('none');
23-
}
24+
public decrease(): void {
25+
if (this.requestsRunning > 0) {
26+
this.requestsRunning--;
27+
if (this.requestsRunning === 0) {
28+
this.updateProgressBar$.emit('none');
2429
}
25-
});
30+
}
2631
}
2732
}

src/app/heroes/shared/hero.service.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {EventEmitter, Injectable} from '@angular/core';
1+
import {Injectable} from '@angular/core';
22
import {HttpClient, HttpHeaders} from '@angular/common/http';
33

44
import {AppConfig} from '../../config/app.config';
@@ -10,14 +10,11 @@ import {TranslateService} from '@ngx-translate/core';
1010

1111
@Injectable()
1212
export class HeroService {
13-
request$: EventEmitter<any>;
14-
1513
private headers: HttpHeaders;
1614
private heroesUrl: string;
1715
private translations: any;
1816

1917
private handleError(error: any) {
20-
this.request$.emit('finished');
2118
if (error instanceof Response) {
2219
return Observable.throw(error.json()['error'] || 'backend server error');
2320
}
@@ -27,8 +24,6 @@ export class HeroService {
2724
constructor(private http: HttpClient,
2825
private translateService: TranslateService,
2926
private snackBar: MatSnackBar) {
30-
this.request$ = new EventEmitter();
31-
3227
this.heroesUrl = AppConfig.endpoints.heroes;
3328
this.headers = new HttpHeaders({'Content-Type': 'application/json'});
3429

@@ -40,34 +35,28 @@ export class HeroService {
4035
}
4136

4237
getAllHeroes(): Observable<Hero[]> {
43-
this.request$.emit('starting');
4438
return this.http.get(this.heroesUrl)
4539
.map(response => {
46-
this.request$.emit('finished');
4740
return response;
4841
})
4942
.catch(error => this.handleError(error));
5043
}
5144

5245
getHeroById(heroId: string): Observable<Hero> {
53-
this.request$.emit('starting');
5446
return this.http.get(this.heroesUrl + '/' + heroId)
5547
.map(response => {
56-
this.request$.emit('finished');
5748
return response;
5849
})
5950
.catch(error => this.handleError(error));
6051
}
6152

6253
createHero(hero: any): Observable<Hero> {
63-
this.request$.emit('starting');
6454
return this.http
6555
.post(this.heroesUrl, JSON.stringify({
6656
name: hero.name,
6757
alterEgo: hero.alterEgo
6858
}), {headers: this.headers})
6959
.map(response => {
70-
this.request$.emit('finished');
7160
this.showSnackBar('heroCreated');
7261
return response;
7362
})
@@ -76,12 +65,10 @@ export class HeroService {
7665

7766
like(hero: Hero) {
7867
if (this.checkIfUserCanVote()) {
79-
this.request$.emit('starting');
8068
const url = `${this.heroesUrl}/${hero.id}/like`;
8169
return this.http
8270
.post(url, {}, {headers: this.headers})
8371
.map((response) => {
84-
this.request$.emit('finished');
8572
localStorage.setItem('votes', '' + (Number(localStorage.getItem('votes')) + 1));
8673
hero.likes += 1;
8774
this.showSnackBar('saved');
@@ -99,11 +86,9 @@ export class HeroService {
9986
}
10087

10188
deleteHeroById(id: any): Observable<Array<Hero>> {
102-
this.request$.emit('starting');
10389
const url = `${this.heroesUrl}/${id}`;
10490
return this.http.delete(url, {headers: this.headers})
10591
.map((response) => {
106-
this.request$.emit('finished');
10792
this.showSnackBar('heroRemoved');
10893
return response;
10994
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from '@angular/common/http';
2+
import {Observable} from 'rxjs/Observable';
3+
import {ProgressBarService} from '../../core/progress-bar.service';
4+
5+
export class ProgressInterceptor implements HttpInterceptor {
6+
constructor(private progressBarService: ProgressBarService) {
7+
}
8+
9+
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
10+
this.progressBarService.increase();
11+
return next
12+
.handle(req)
13+
.do(event => {
14+
if (event instanceof HttpResponse) {
15+
this.progressBarService.decrease();
16+
}
17+
});
18+
}
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from '@angular/common/http';
2+
import {Observable} from 'rxjs/Observable';
3+
import {LoggerService} from '../../core/logger.service';
4+
5+
export class TimingInterceptor implements HttpInterceptor {
6+
constructor() {
7+
}
8+
9+
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
10+
const started = Date.now();
11+
return next
12+
.handle(req)
13+
.do(event => {
14+
if (event instanceof HttpResponse) {
15+
const elapsed = Date.now() - started;
16+
LoggerService.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`);
17+
}
18+
});
19+
}
20+
}

src/polyfills.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ import 'rxjs/add/observable/throw';
8282

8383
import 'rxjs/add/operator/catch';
8484
import 'rxjs/add/operator/startWith';
85+
import 'rxjs/add/operator/do';
86+
8587

8688
/**
8789
* Need to import hammer for Angular Material support.

0 commit comments

Comments
 (0)