Skip to content

Commit 0332cc0

Browse files
authored
Merge pull request #73 from mpalourdio/feature_request37
Minimum duration for spinner visibility. Fixes #37
2 parents 2cd50b9 + 41f6135 commit 0332cc0

File tree

13 files changed

+272
-54
lines changed

13 files changed

+272
-54
lines changed

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,9 @@ language: node_js
33
node_js:
44
- lts/*
55
- node
6+
script:
7+
- yarn test --code-coverage
8+
- yarn build
9+
10+
after_script:
11+
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js

CHANGELOG.md

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

3+
## v2.1.0
4+
5+
This release introduces the **minimum duration** option. It gives the possibility to force a minimum duration during which the spinner should be visible.
6+
You can mix this parameter with the **debounce delay** option :
7+
8+
```xml
9+
<spinner
10+
[debounceDelay]="100"
11+
[minDuration]="300">
12+
</spinner>
13+
```
14+
15+
```
16+
Debounce delay: 100ms
17+
Min. duration time: 300ms
18+
---0ms--------100ms------------180ms-----------400ms--
19+
----|----------|-----------------|---------------|----
20+
req starts spinner shows req ends spinner hides
21+
```
22+
23+
``SpinnerVisibilityService#visibilityObservable`` and ``PendingInterceptorService#pendingRequestsStatus`` have been respectively deprecated in favor of ``visibilityObservable$`` and ``pendingRequestsStatus$`` (note the **$**).
24+
325
## v2.0.0
426

527
The module bundling now uses [ng-packagr](https://github.com/dherges/ng-packagr).

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# ng-http-loader
22

33
[![Build Status](https://travis-ci.org/mpalourdio/ng-http-loader.svg?branch=master)](https://travis-ci.org/mpalourdio/ng-http-loader)
4+
[![Coverage Status](https://coveralls.io/repos/github/mpalourdio/ng-http-loader/badge.svg?branch=master)](https://coveralls.io/github/mpalourdio/ng-http-loader?branch=master)
45
[![npm](https://img.shields.io/npm/v/ng-http-loader.svg)](https://www.npmjs.com/package/ng-http-loader)
56
[![npm](https://img.shields.io/npm/dm/ng-http-loader.svg)](https://www.npmjs.com/package/ng-http-loader)
67

@@ -78,13 +79,13 @@ In your app.component.html, simply add :
7879

7980
## Customizing the spinner
8081

81-
You can customize the **background-color**, the **spinner type** and the **debounce delay** (ie. after how many milliseconds the spinner will be displayed, if needed):
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):
8283
```xml
8384
<spinner
8485
[backgroundColor]="'#ff0000'"
8586
[spinner]="spinkit.skWave"
86-
[debounceDelay]="200"
87-
>
87+
[debounceDelay]="100"
88+
[minDuration]="300">
8889
</spinner>
8990
```
9091

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ng-http-loader",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"scripts": {
55
"ng": "ng",
66
"build": "ng build",
@@ -52,6 +52,7 @@
5252
"@types/node": "~8.9.4",
5353
"codelyzer": "~4.2.1",
5454
"core-js": "^2.5.4",
55+
"coveralls": "^3.0.1",
5556
"jasmine-core": "~2.99.1",
5657
"jasmine-spec-reporter": "~4.2.1",
5758
"karma": "~2.0.0",
@@ -60,7 +61,7 @@
6061
"karma-jasmine": "~1.1.1",
6162
"karma-jasmine-html-reporter": "^0.2.2",
6263
"karma-phantomjs-launcher": "^1.0.4",
63-
"ng-packagr": "^3.0.0-rc.5",
64+
"ng-packagr": "^3.0.0",
6465
"phantomjs-prebuilt": "^2.1.14",
6566
"rxjs": "^6.0.0",
6667
"ts-node": "~5.0.1",

src/lib/components/spinner/spinner.component.html

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,42 @@
33
<ng-container *ngComponentOutlet="entryComponent"></ng-container>
44

55
<sk-cube-grid
6-
*ngIf="spinner === Spinkit.skCubeGrid"
6+
*ngIf="spinner === spinkit.skCubeGrid"
77
[backgroundColor]="backgroundColor">
88
</sk-cube-grid>
99

1010
<sk-chasing-dots
11-
*ngIf="spinner === Spinkit.skChasingDots"
11+
*ngIf="spinner === spinkit.skChasingDots"
1212
[backgroundColor]="backgroundColor">
1313
</sk-chasing-dots>
1414

1515
<sk-double-bounce
16-
*ngIf="spinner === Spinkit.skDoubleBounce"
16+
*ngIf="spinner === spinkit.skDoubleBounce"
1717
[backgroundColor]="backgroundColor">
1818
</sk-double-bounce>
1919

2020
<sk-rotating-plane
21-
*ngIf="spinner === Spinkit.skRotatingPlane"
21+
*ngIf="spinner === spinkit.skRotatingPlane"
2222
[backgroundColor]="backgroundColor">
2323
</sk-rotating-plane>
2424

2525
<sk-spinner-pulse
26-
*ngIf="spinner === Spinkit.skSpinnerPulse"
26+
*ngIf="spinner === spinkit.skSpinnerPulse"
2727
[backgroundColor]="backgroundColor">
2828
</sk-spinner-pulse>
2929

3030
<sk-three-bounce
31-
*ngIf="spinner === Spinkit.skThreeBounce"
31+
*ngIf="spinner === spinkit.skThreeBounce"
3232
[backgroundColor]="backgroundColor">
3333
</sk-three-bounce>
3434

3535
<sk-wandering-cubes
36-
*ngIf="spinner === Spinkit.skWanderingCubes"
36+
*ngIf="spinner === spinkit.skWanderingCubes"
3737
[backgroundColor]="backgroundColor">
3838
</sk-wandering-cubes>
3939

4040
<sk-wave
41-
*ngIf="spinner === Spinkit.skWave"
41+
*ngIf="spinner === spinkit.skWave"
4242
[backgroundColor]="backgroundColor">
4343
</sk-wave>
4444

src/lib/components/spinner/spinner.component.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
*/
99

1010
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
11-
import { merge, Observable, Subscription, timer } from 'rxjs';
12-
import { debounce } from 'rxjs/operators';
11+
import { EMPTY, merge, Observable, Subscription, timer } from 'rxjs';
12+
import { debounce, delayWhen } from 'rxjs/operators';
1313
import { PendingInterceptorService } from '../../services/pending-interceptor.service';
1414
import { SpinnerVisibilityService } from '../../services/spinner-visibility.service';
1515
import { Spinkit } from '../../spinkits';
@@ -21,9 +21,10 @@ import { Spinkit } from '../../spinkits';
2121
})
2222
export class SpinnerComponent implements OnDestroy, OnInit {
2323
public isSpinnerVisible: boolean;
24+
public spinkit = Spinkit;
2425
private subscriptions: Subscription;
26+
private startTime: number;
2527

26-
public Spinkit = Spinkit;
2728
@Input()
2829
public backgroundColor: string;
2930
@Input()
@@ -33,12 +34,17 @@ export class SpinnerComponent implements OnDestroy, OnInit {
3334
@Input()
3435
public debounceDelay = 0;
3536
@Input()
37+
public minDuration = 0;
38+
@Input()
3639
public entryComponent: any = null;
3740

3841
constructor(private pendingInterceptorService: PendingInterceptorService, private spinnerVisibilityService: SpinnerVisibilityService) {
3942
this.subscriptions = merge(
40-
this.pendingInterceptorService.pendingRequestsStatus.pipe(debounce(this.handleDebounce.bind(this))),
41-
this.spinnerVisibilityService.visibilityObservable,
43+
this.pendingInterceptorService.pendingRequestsStatus$.pipe(
44+
debounce(this.handleDebounceDelay.bind(this)),
45+
delayWhen(this.handleMinDuration.bind(this))
46+
),
47+
this.spinnerVisibilityService.visibilityObservable$,
4248
)
4349
.subscribe(this.handleSpinnerVisibility().bind(this));
4450
}
@@ -71,11 +77,24 @@ export class SpinnerComponent implements OnDestroy, OnInit {
7177
return v => this.isSpinnerVisible = v;
7278
}
7379

74-
private handleDebounce(hasPendingRequests: boolean): Observable<number> {
75-
if (hasPendingRequests) {
80+
private handleDebounceDelay(hasPendingRequests: boolean): Observable<number | never> {
81+
if (hasPendingRequests && !!this.debounceDelay) {
7682
return timer(this.debounceDelay);
7783
}
7884

79-
return timer(0);
85+
return EMPTY;
86+
}
87+
88+
private handleMinDuration(hasPendingRequests: boolean): Observable<number> {
89+
if (hasPendingRequests || !this.minDuration) {
90+
this.startTime = Date.now();
91+
92+
return timer(0);
93+
}
94+
95+
const timerObservable = timer(this.minDuration - (Date.now() - this.startTime));
96+
this.startTime = null;
97+
98+
return timerObservable;
8099
}
81100
}

src/lib/services/pending-interceptor.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ export class PendingInterceptorService implements HttpInterceptor {
2121
private _filteredUrlPatterns: RegExp[] = [];
2222
private _forceByPass: boolean;
2323

24+
/** @deprecated Deprecated in favor of pendingRequestsStatus$ */
2425
get pendingRequestsStatus(): Observable<boolean> {
2526
return this._pendingRequestsStatus.asObservable();
2627
}
2728

29+
get pendingRequestsStatus$(): Observable<boolean> {
30+
return this.pendingRequestsStatus;
31+
}
32+
2833
get pendingRequests(): number {
2934
return this._pendingRequests;
3035
}

src/lib/services/spinner-visibility.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ export class SpinnerVisibilityService {
2020
constructor(private pendingInterceptorService: PendingInterceptorService) {
2121
}
2222

23+
/** @deprecated Deprecated in favor of visibilityObservable$ */
2324
get visibilityObservable(): Observable<boolean> {
2425
return this._visibilitySubject.asObservable();
2526
}
2627

28+
get visibilityObservable$(): Observable<boolean> {
29+
return this.visibilityObservable;
30+
}
31+
2732
public show(): void {
2833
this.pendingInterceptorService.forceByPass = true;
2934
this._visibilitySubject.next(true);

0 commit comments

Comments
 (0)