Skip to content

Instantly share code, notes, and snippets.

@viktor-shmigol
Last active October 11, 2016 16:44
Show Gist options
  • Save viktor-shmigol/7772d296aac685cad108cf9fccdd7e32 to your computer and use it in GitHub Desktop.
Save viktor-shmigol/7772d296aac685cad108cf9fccdd7e32 to your computer and use it in GitHub Desktop.
import { Http, RequestOptions, ConnectionBackend, RequestOptionsArgs, Response } from '@angular/http'
import { Injectable } from '@angular/core'
import { PromiseTrackerService } from './promise_traker'
import { Observable } from 'rxjs'
import 'rxjs/add/operator/map';
export class HttpLoading extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private promiseTrackerService: PromiseTrackerService ) {
super(backend, defaultOptions);
}
get(url: string, options?: RequestOptionsArgs):Observable<Response> {
var Deferred = function() {
this.promise = new Promise((function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}).bind(this));
this.then = this.promise.then.bind(this.promise);
this.catch = this.promise.catch.bind(this.promise);
};
var d = new Deferred();
this.promiseTrackerService.reset({
promiseList: [d.promise],
delay: 1300, // Show loader if the response is taking longer than 1300 sec
minDuration: 1300
});
return super.get(url, options).map(
(resp) => {
d.resolve();
return resp;
}
).catch(
error=> {
d.resolve();
return Observable.throw(error || 'backend server error');
}
)
}
}
in app.ts
export class MyApp {
constructor(private tracker: PromiseTrackerService) { }
and to bootstrap =>
{ provide: Http, useFactory: (backend: XHRBackend, defaultOptions: RequestOptions, promiseTrackerService: PromiseTrackerService) => new HttpLoading(backend, defaultOptions, promiseTrackerService),
deps: [XHRBackend, RequestOptions, PromiseTrackerService]
}
app.html
<div *ngIf="tracker.isActive();" class="search-loader-wrap">
<img class="search-loader" src="build/images/loading.gif"/>
</div>
promiseTrackerService.ts
import { Injectable } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
@Injectable()
export class PromiseTrackerService {
promiseList: Array<Promise<any> | Subscription> = [];
delayPromise: number | any;
durationPromise: number | any;
delayJustFinished: boolean = false;
minDuration: number;
reset(options: IPromiseTrackerOptions) {
this.minDuration = options.minDuration;
this.promiseList = [];
options.promiseList.forEach(promise => {
if (!promise || promise['busyFulfilled']) {
return;
}
this.addPromise(promise);
});
if (this.promiseList.length === 0) {
return;
}
this.delayJustFinished = false;
if (options.delay) {
this.delayPromise = setTimeout(
() => {
this.delayPromise = null;
this.delayJustFinished = true;
},
options.delay
);
}
if (options.minDuration) {
this.durationPromise = setTimeout(
() => {
this.durationPromise = null;
},
options.minDuration + (options.delay || 0)
);
}
}
private addPromise(promise: Promise<any> | Subscription) {
if (this.promiseList.indexOf(promise) !== -1) {
return;
}
this.promiseList.push(promise);
if (promise instanceof Promise) {
promise.then.call(
promise,
() => this.finishPromise(promise),
() => this.finishPromise(promise)
);
}
else if (promise instanceof Subscription) {
promise.add(() => this.finishPromise(promise));
}
}
private finishPromise(promise: Promise<any> | Subscription) {
promise['busyFulfilled'] = true;
const index = this.promiseList.indexOf(promise);
if (index === -1) {
return;
}
this.promiseList.splice(index, 1);
}
isActive() {
if (this.delayPromise) {
return false;
}
if (!this.delayJustFinished) {
if (this.durationPromise) {
return true;
}
return this.promiseList.length > 0;
}
this.delayJustFinished = false;
if (this.promiseList.length === 0) {
this.durationPromise = null;
}
return this.promiseList.length > 0;
}
}
export interface IPromiseTrackerOptions {
minDuration: number;
delay: number;
promiseList: Promise<any>[];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment