4

So I am trying to implement a custom XHRBackend for my Angular 2 app. This is my class:

import {Request, XHRBackend, BrowserXhr, ResponseOptions, XSRFStrategy} from "@angular/http";
import "rxjs/add/operator/catch";
import "rxjs/add/observable/throw";
import {SlimLoadingBarService} from "ng2-slim-loading-bar";

export class LoadingBarXHRBackend extends XHRBackend {
    constructor(_browserXhr: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy, private slimLoadingBarService: SlimLoadingBarService) {
        super(_browserXhr, _baseResponseOptions, _xsrfStrategy);
    }

    createConnection(request: Request) {
        this.slimLoadingBarService.start();

        let xhrConnection = super.createConnection(request);

        xhrConnection.response.share().subscribe(() => {
            this.slimLoadingBarService.complete();
        });

        return xhrConnection;
    }

}

As you can see I tried using the .share() method as described here, but it does not work the way I expect it to.

I want to "hook in" to the creation and completion of an XHR request to display a loading bar. But if I leave that .share() call out I get a separate HTTP request for each .subscribe() call I make.

But if I use .share() my second Subscription won't be executed at all :(

What am I doing wrong? Thanks.

John Reese
  • 583
  • 2
  • 6
  • 17

1 Answers1

3

Try this:

createConnection(request: Request) {
    this.slimLoadingBarService.start();

    let xhrConnection = super.createConnection(request).response.share();

    xhrConnection.subscribe(() => {
        this.slimLoadingBarService.complete();
    });

    return xhrConnection;
}

You need to share() before subscribing and returning, so that both the internal and the external one gets the multicasted version of the observable.

Note however that share turns the obseravble in to a hot observable, so you might want to do this instead:

createConnection(request: Request) {
    return Observable.defer(() => {
        this.slimLoadingBarService.start();

        return super.createConnection(request).response
            .do(() => this.slimLoadingBarService.complete());
    });
}

Observable.defer means that none of the code inside of it will be executed untill you actually subscribe to it. The do operator taps in to the event stream without affecting the stream.

Nypan
  • 6,980
  • 3
  • 21
  • 28