Skip to content

Commit ba8fcee

Browse files
authored
Merge pull request #94 from mpalourdio/prepare_v310
Prepare v3.1.0. Fixes #87 && Fixes #90
2 parents 2bc0d3f + 91be823 commit ba8fcee

File tree

8 files changed

+548
-298
lines changed

8 files changed

+548
-298
lines changed

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
# Changelog
22

3+
## v3.1.0
4+
5+
Awesome contribution by [gnom7](https://github.com/gnom7)
6+
- Better handling of sequential HTTP requests. Particularly when mixed with the ``minDuration`` option. See [this issue](https://github.com/mpalourdio/ng-http-loader/issues/89) for reference.
7+
8+
```
9+
Min. duration time: 300ms
10+
---0ms------------------------------200ms-------280ms----------------400ms|
11+
----|---------------------------------------------|-----------------------|
12+
(req1 starts and spinner shows) (req1 ends) (req2 starts) (req2 ends and spinner hides)
13+
```
14+
15+
Before this, minDuration would have been applied to both HTTP requests.
16+
17+
- Added the ``extraDuration`` option:
18+
- This option make the spinner visible a certain amount of time after the moment when it should have naturally been hidden. This avoids flickering when, for example, multiple HTTP requests are ran sequentially.
19+
- See [this issue](https://github.com/mpalourdio/ng-http-loader/issues/90) for reference
20+
21+
```
22+
Extra duration time: 60ms
23+
---0ms----------200ms------260ms---- |
24+
----|------------|----------|--------|
25+
req starts req ends spinner hides
26+
```
27+
328
## v3.0.0
429

530
- All existing deprecations have been removed.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,14 @@ In your app.component.html, simply add:
7979

8080
## Customizing the spinner
8181

82-
You can customize the **background-color**, the **spinner type**, the **debounce delay** (ie. after how many milliseconds the spinner will be visible, if needed), the **minimum duration** (ie. how many milliseconds should the spinner be visible at least):
82+
You can customize the **background-color**, the **spinner type**, the **debounce delay** (ie. after how many milliseconds the spinner will be visible, if needed), the **minimum duration** (ie. how many milliseconds should the spinner be visible at least), the **extra duration** (ie. how many extra milliseconds should the spinner be visible):
8383
```xml
8484
<ng-http-loader
8585
[backgroundColor]="'#ff0000'"
8686
[spinner]="spinkit.skWave"
8787
[debounceDelay]="100"
88-
[minDuration]="300">
88+
[minDuration]="300"
89+
[extraDuration]="300">
8990
</ng-http-loader>
9091
```
9192

angular.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"styleext": "scss"
1212
}
1313
},
14-
"architect": {
14+
"targets": {
1515
"build": {
1616
"builder": "@angular-devkit/build-ng-packagr:build",
1717
"options": {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ng-http-loader",
3-
"version": "3.1.0-beta.0",
3+
"version": "3.1.0",
44
"scripts": {
55
"ng": "ng",
66
"build": "ng build",
@@ -64,7 +64,7 @@
6464
"karma-firefox-launcher": "^1.1.0",
6565
"karma-jasmine": "~1.1.2",
6666
"karma-jasmine-html-reporter": "^0.2.2",
67-
"ng-packagr": "^3.0.0",
67+
"ng-packagr": "^4.1.0",
6868
"rxjs": "~6.2.0",
6969
"ts-node": "~7.0.0",
7070
"tsickle": ">=0.29.0",

src/lib/components/ng-http-loader.component.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ export class NgHttpLoaderComponent implements OnDestroy, OnInit {
5858
}
5959

6060
private initializeSubscription() {
61-
const [showSpinner, hideSpinner] = partition((h: boolean) => h)(this.pendingInterceptorService.pendingRequestsStatus$);
61+
const [showSpinner$, hideSpinner$] = partition((h: boolean) => h)(this.pendingInterceptorService.pendingRequestsStatus$);
6262

6363
this.subscriptions = merge(
6464
this.pendingInterceptorService.pendingRequestsStatus$.pipe(
65-
switchMap(() => showSpinner.pipe(debounce(() => timer(this.debounceDelay))))
65+
switchMap(() => showSpinner$.pipe(debounce(() => timer(this.debounceDelay))))
6666
),
67-
showSpinner.pipe(
68-
switchMap(() => hideSpinner.pipe(debounce(() => this.getHidingTimer())))
67+
showSpinner$.pipe(
68+
switchMap(() => hideSpinner$.pipe(debounce(() => this.getVisibilityTimer())))
6969
),
7070
this.spinnerVisibilityService.visibilityObservable$,
7171
)
@@ -112,14 +112,13 @@ export class NgHttpLoaderComponent implements OnDestroy, OnInit {
112112
}
113113

114114
private handleSpinnerVisibility(showSpinner: boolean): void {
115-
const now = Date.now();
116-
if (showSpinner && this.visibleUntil <= now) {
117-
this.visibleUntil = now + this.minDuration;
115+
if (showSpinner) {
116+
this.visibleUntil = Date.now() + this.minDuration;
118117
}
119118
this.isSpinnerVisible = showSpinner;
120119
}
121120

122-
private getHidingTimer(): Observable<number> {
121+
private getVisibilityTimer(): Observable<number> {
123122
return timer(Math.max(this.extraDuration, this.visibleUntil - Date.now()));
124123
}
125124
}

src/test/components/ng-http-loader.component.spec.ts

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,34 @@ describe('NgHttpLoaderComponent', () => {
528528
}
529529
)));
530530

531+
it('should correctly handle the extra spinner duration for a single HTTP request', fakeAsync(inject(
532+
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
533+
component.extraDuration = 5000;
534+
http.get('/fake').subscribe();
535+
536+
// the HTTP request is pending for 1 second now
537+
tick(1000);
538+
expect(component.isSpinnerVisible).toBeTruthy();
539+
540+
// the HTTP request is pending for 2 seconds now
541+
tick(1000);
542+
expect(component.isSpinnerVisible).toBeTruthy();
543+
544+
// the HTTP request is finally over, the spinner is still visible
545+
httpMock.expectOne('/fake').flush({});
546+
tick();
547+
expect(component.isSpinnerVisible).toBeTruthy();
548+
549+
// 4 seconds after the HTTP request is over, the spinner is still visible
550+
tick(4000);
551+
expect(component.isSpinnerVisible).toBeTruthy();
552+
553+
// the spinner is not visible anymore after 5 seconds
554+
tick(1000);
555+
expect(component.isSpinnerVisible).toBeFalsy();
556+
}
557+
)));
558+
531559
it('should correctly handle the minimum spinner duration for multiple HTTP requests', fakeAsync(inject(
532560
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
533561
component.minDuration = 5000;
@@ -573,6 +601,55 @@ describe('NgHttpLoaderComponent', () => {
573601
}
574602
)));
575603

604+
it('should correctly handle the extra spinner duration for multiple HTTP requests', fakeAsync(inject(
605+
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
606+
component.extraDuration = 5000;
607+
608+
function runQuery(url: string): Observable<any> {
609+
return http.get(url);
610+
}
611+
612+
forkJoin([runQuery('/fake'), runQuery('/fake2')]).subscribe();
613+
614+
const firstRequest = httpMock.expectOne('/fake');
615+
const secondRequest = httpMock.expectOne('/fake2');
616+
617+
// the HTTP requests are pending for 1 second now
618+
tick(1000);
619+
expect(component.isSpinnerVisible).toBeTruthy();
620+
621+
// the HTTP requests are pending for 2 seconds now
622+
tick(1000);
623+
expect(component.isSpinnerVisible).toBeTruthy();
624+
625+
// the first HTTP request is finally over, the spinner is still visible
626+
firstRequest.flush({});
627+
tick();
628+
expect(component.isSpinnerVisible).toBeTruthy();
629+
630+
// the second HTTP request is still pending after 3 seconds
631+
tick(1000);
632+
expect(component.isSpinnerVisible).toBeTruthy();
633+
634+
// the second HTTP request is still pending after 4 seconds
635+
tick(1000);
636+
expect(component.isSpinnerVisible).toBeTruthy();
637+
638+
// the second HTTP request is finally over too, the spinner is still visible
639+
secondRequest.flush({});
640+
tick();
641+
expect(component.isSpinnerVisible).toBeTruthy();
642+
643+
// After 4 seconds, the spinner is still visible
644+
tick(4000);
645+
expect(component.isSpinnerVisible).toBeTruthy();
646+
647+
// After 5 seconds, the spinner is hidden
648+
tick(1000);
649+
expect(component.isSpinnerVisible).toBeFalsy();
650+
}
651+
)));
652+
576653
it('should correctly handle the minimum spinner duration for multiple HTTP requests ran one after the others', fakeAsync(inject(
577654
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
578655
component.minDuration = 2000;
@@ -673,6 +750,17 @@ describe('NgHttpLoaderComponent', () => {
673750
}
674751
));
675752

753+
it('should be possible to set the extra duration without side effect on manual show/hide', inject(
754+
[SpinnerVisibilityService], (spinner: SpinnerVisibilityService) => {
755+
component.extraDuration = 10000;
756+
spinner.show();
757+
expect(component.isSpinnerVisible).toBeTruthy();
758+
759+
spinner.hide();
760+
expect(component.isSpinnerVisible).toBeFalsy();
761+
}
762+
));
763+
676764
it('should be possible to mix debounce delay and minimum duration', fakeAsync(inject(
677765
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
678766
// the spinner should not be visible the first second, then visible for 5 seconds
@@ -702,6 +790,41 @@ describe('NgHttpLoaderComponent', () => {
702790
tick(2999);
703791
expect(component.isSpinnerVisible).toBeTruthy();
704792

793+
// after 6 seconds (1s for debounce + 5s extra. duration), the spinner is hidden
794+
tick(1);
795+
expect(component.isSpinnerVisible).toBeFalsy();
796+
}
797+
)));
798+
799+
it('should be possible to mix debounce delay and extra duration', fakeAsync(inject(
800+
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
801+
// the spinner should not be visible the first second, then visible for 5 seconds
802+
component.extraDuration = 5000;
803+
component.debounceDelay = 1000;
804+
805+
http.get('/fake').subscribe();
806+
807+
// the HTTP request is pending for 0,5 second now - spinner not visible because debounce
808+
tick(500);
809+
expect(component.isSpinnerVisible).toBeFalsy();
810+
811+
// the HTTP request is pending for 1 second now - spinner visible
812+
tick(500);
813+
expect(component.isSpinnerVisible).toBeTruthy();
814+
815+
// the HTTP request is finally over, the spinner is still visible
816+
httpMock.expectOne('/fake').flush({});
817+
tick();
818+
expect(component.isSpinnerVisible).toBeTruthy();
819+
820+
// after 3 seconds, the spinner is still visible
821+
tick(2000);
822+
expect(component.isSpinnerVisible).toBeTruthy();
823+
824+
// after 5,999 seconds, the spinner is still visible
825+
tick(2999);
826+
expect(component.isSpinnerVisible).toBeTruthy();
827+
705828
// after 6 seconds (1s for debounce + 5s min. duration), the spinner is hidden
706829
tick(1);
707830
expect(component.isSpinnerVisible).toBeFalsy();

tsconfig.lib.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"noImplicitAny": true,
1111
"noImplicitReturns": true,
1212
"types": [],
13+
"baseUrl": "./",
1314
"lib": [
1415
"dom",
1516
"es2015"
@@ -21,8 +22,7 @@
2122
"strictMetadataEmit": true,
2223
"fullTemplateTypeCheck": true,
2324
"strictInjectionParameters": true,
24-
"flatModuleId": "AUTOGENERATED",
25-
"flatModuleOutFile": "AUTOGENERATED"
25+
"enableResourceInlining": true
2626
},
2727
"exclude": [
2828
"./src/test.ts",

0 commit comments

Comments
 (0)