0

I'm trying to build a small application using angular2 with more reusable components. Here, I want to have a Loader Service which gets executed on every xhr call.

For that, this is what I came up with

  1. Using Promise

    export class SpinnerService {
    
        showSpinner = false;
    
        spinnerPromise(observableToWaitFor: Observable<any>, text?: string): Promise<any> {
            this.showSpinner = true;
            return promiseToWaitFor.toPromise()
                .then((data) => { this.showSpinner = false; return data; });
        }   
    
    }  
    

    This is how I'm consuming my SpinnerService

        constructor(private requestService: RequestService, private spinnerService: SpinnerService) { }
    
        signin(username: string, password: string) {
            let url = _.template(API_Constant.LOGIN)({ username: username });
            return this.spinnerService.spinnerPromise(this.requestService
                .makeRequest(url, RequestMethod.Get))
                .then(data => {
                    let peoples = data.results;
                    let found = _.find(peoples, (p: any) => p.name.toLowerCase() === username.toLowerCase());
                    if (found && found.birth_year === password) {
    
                    } else {
                        return Promise.reject('Invalid username or password');
                    }
                });
        }
    }
    

    It works fine till some extent. But I'm not very well convinced with the usage, as it restrict the AuthService to consume Promise.

  2. Using Observable

    I'm a beginner in using Observable, so I don't know how difficult or easy it is to implement a generic Loader Service.

This is what I tried

@Injectable()
export class SpinnerService {

    showSpinner = false;
    public consumer: ReplaySubject<any> = new ReplaySubject(1);

    spinnerPromise(observableToWaitFor: Observable<any>, text?: string) {
        this.showSpinner = true;
        return observableToWaitFor.subscribe(
            response => this.consumer.next(response),
            error => { this.showSpinner = false; },
            () => { this.showSpinner = false; }
        );
    }

}

This returns a Subscription. But is there a way to update the showSpinner without subscribing it.

Tushar
  • 1,115
  • 1
  • 10
  • 26
  • You can use `.do()` to perform side-effects but this assumes you'll subscribe to the Observable later anyway. – martin Apr 09 '17 at 12:15
  • @martin what if api call failed, would .do() still get executed? – Tushar Apr 09 '17 at 12:17
  • `do()` takes three callbacks. For `next`, `error` and `complete` signals so you can choose what you want to handle. – martin Apr 09 '17 at 12:20
  • Instead of creating it as a service you can create as a custom common component as in this [**answer**](http://stackoverflow.com/questions/42963444/angular-2-material-progress-spinner-display-as-overlay/43243097#43243097) – Aravind Apr 09 '17 at 12:32
  • @Aravind I already have a component SpinnerComponent which interacts with this SpinnerService which shows/hides the loader. – Tushar Apr 09 '17 at 12:44
  • you can directly use the component where ever you need to show the spinner. why you use subject and complicate – Aravind Apr 09 '17 at 12:47

1 Answers1

0

Finally got it working..the only change I had to do, is to use finally like this

export class SpinnerService {

    showSpinner = false;
    spinnerPromise(observableToWaitFor: Observable<any>, text?: string) {
        this.showSpinner = true;
        return observableToWaitFor.finally(() => this.showSpinner = false);            
    }
}
Tushar
  • 1,115
  • 1
  • 10
  • 26