Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v2.3.0

This release adds the possibility to filter HTTP requests that should not be handled by the interceptor by providing an array of HTTP headers to the component's ``filteredHeaders`` property.

## v2.2.0

This release adds the possibility to filter HTTP requests that should not be handled by the interceptor by providing an array of HTTP methods to the component's ``filteredMethods`` property.
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,23 @@ You can define your own loader component in place of the built-in ones. The need

You can find some short examples [here](https://gist.github.com/mpalourdio/2c0bec03d610b24ff49db649fbb69a48) and [here](https://gist.github.com/mpalourdio/e05b4495de2abeeecfcf92d70e4ef93e).

## Requests filtering by URL or by HTTP method
## Requests filtering by URL, HTTP method or HTTP headers

You can filter the http requests that shouldn't be caught by the interceptor by providing **an array of regex patterns**:
```xml
<spinner [filteredUrlPatterns]="['\\d', '[a-zA-Z]', 'my-api']"></spinner>
```

You can also filter the http requests by providing **an array of HTTP methods** (case insensitive):
You can filter the http requests by providing **an array of HTTP methods** (case insensitive):
```xml
<spinner [filteredMethods]="['gEt', 'POST', 'PuT']"></spinner>
```

You can also filter the http requests by providing **an array of HTTP headers** (case insensitive):
```xml
<spinner [filteredHeaders]="['hEaDeR', 'AnoTheR-HeAdEr']"></spinner>
```

## Manually show and hide the spinner

You can manually show and hide the spinner component if needed. You must use the ``SpinnerVisibilityService`` for this purpose.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ng-http-loader",
"version": "2.2.0",
"version": "2.3.0",
"scripts": {
"ng": "ng",
"build": "ng build",
Expand Down
7 changes: 7 additions & 0 deletions src/lib/components/spinner/spinner.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export class SpinnerComponent implements OnDestroy, OnInit {
@Input()
public filteredMethods: string[] = [];
@Input()
public filteredHeaders: string[] = [];
@Input()
public debounceDelay = 0;
@Input()
public minDuration = 0;
Expand Down Expand Up @@ -68,6 +70,11 @@ export class SpinnerComponent implements OnDestroy, OnInit {
throw new TypeError('`filteredMethods` must be an array.');
}
this.pendingInterceptorService.filteredMethods = this.filteredMethods;

if (!(this.filteredHeaders instanceof Array)) {
throw new TypeError('`filteredHeaders` must be an array.');
}
this.pendingInterceptorService.filteredHeaders = this.filteredHeaders;
}

ngOnDestroy(): void {
Expand Down
12 changes: 12 additions & 0 deletions src/lib/services/pending-interceptor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class PendingInterceptorService implements HttpInterceptor {
private _pendingRequestsStatus: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);
private _filteredUrlPatterns: RegExp[] = [];
private _filteredMethods: string[] = [];
private _filteredHeaders: string[] = [];
private _forceByPass: boolean;

/** @deprecated Deprecated in favor of pendingRequestsStatus$ */
Expand All @@ -43,6 +44,10 @@ export class PendingInterceptorService implements HttpInterceptor {
this._filteredMethods = httpMethods;
}

set filteredHeaders(value: string[]) {
this._filteredHeaders = value;
}

set forceByPass(value: boolean) {
this._forceByPass = value;
}
Expand All @@ -59,9 +64,16 @@ export class PendingInterceptorService implements HttpInterceptor {
});
}

private shouldBypassHeader(req: HttpRequest<any>): boolean {
return this._filteredHeaders.some(e => {
return req.headers.has(e);
});
}

private shouldBypass(req: HttpRequest<any>): boolean {
return this.shouldBypassUrl(req.urlWithParams)
|| this.shouldBypassMethod(req)
|| this.shouldBypassHeader(req)
|| this._forceByPass;
}

Expand Down
46 changes: 46 additions & 0 deletions src/test/components/spinner/spinner.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,23 @@ describe('SpinnerComponent', () => {
}
)));

it('should not show the spinner if the request is filtered by HTTP header', fakeAsync(inject(
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
component.filteredHeaders.push('header-to-filter');
fixture.detectChanges();

http.get('/fake', {
headers: {
'header-to-filter': 'value'
}
}).subscribe();

tick();
expect(component.isSpinnerVisible).toBeFalsy();
httpMock.expectOne('/fake').flush({});
}
)));

it('should take care of query strings in filteredUrlPatterns', fakeAsync(inject(
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
component.filteredUrlPatterns.push('bar');
Expand Down Expand Up @@ -219,6 +236,30 @@ describe('SpinnerComponent', () => {
}
)));

it('should correctly filter by HTTP header with several requests', fakeAsync(inject(
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
component.filteredHeaders.push('My-HeAdER');
fixture.detectChanges();

http.get('/12345', {
headers: {
'my-header': 'value'
}
}).subscribe();
tick();
expect(component.isSpinnerVisible).toBeFalsy();
httpMock.expectOne('/12345').flush({});

http.get('/fake').subscribe();
tick();
expect(component.isSpinnerVisible).toBeTruthy();
httpMock.expectOne('/fake').flush({});

tick();
expect(component.isSpinnerVisible).toBeFalsy();
}
)));

it('should throw an error if filteredUrlPatterns is not an array', () => {
component.filteredUrlPatterns = null;
expect(() => fixture.detectChanges()).toThrow(new Error('`filteredUrlPatterns` must be an array.'));
Expand All @@ -229,6 +270,11 @@ describe('SpinnerComponent', () => {
expect(() => fixture.detectChanges()).toThrow(new Error('`filteredMethods` must be an array.'));
});

it('should throw an error if filteredHeaders is not an array', () => {
component.filteredHeaders = null;
expect(() => fixture.detectChanges()).toThrow(new Error('`filteredHeaders` must be an array.'));
});

it('should show the spinner even if the component is created after the HTTP request is performed', fakeAsync(inject(
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
http.get('/fake').subscribe();
Expand Down
3 changes: 0 additions & 3 deletions src/test/services/pending-interceptor.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,6 @@ describe('PendingInterceptorService', () => {

const testRequest = httpMock.expectOne('/fake');
testRequest.flush({}, {
'headers': {
'name': 'useless-header'
},
'status': 404,
'statusText': statusText
});
Expand Down
Loading