I think that your issue is trickiest than it appears at a first sight ;-) In fact, XHR doesn't support streaming so when the first callback registered within the subscribe
method is called you already received all the data.
That said XHR supports the onprogress
event (see this plunkr: http://plnkr.co/edit/8MDO2GsCGiOJd2y2XbQk?p=preview). This allows to get hints about the progress of the download. This isn't supported out of the box by Angular2 but you
@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
constructor(private service:ProgressService) {}
build(): any {
let xhr = super.build();
xhr.onprogress = (event) => {
service.progressEventObservable.next(event);
};
return <any>(xhr);
}
}
and override the BrowserXhr
provider with the extended:
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide(BrowserXhr, { useClass: CustomBrowserXhr })
]);
The progress service could be implemented this way:
export class ProgressService {
progressEventObservable:Subject<any> = new Subject();
}
Your service could subscribe on the progress service to be notified when the download actually starts (i.e. the first time the next
method of progressEventObservable
is called for the request):
getList() {
var subscription = this.progressService.subscribe(event => {
if (!this.spinner) {
this.spinner = true;
}
});
this._http.get('../fake-data/someFile.json')
.map(response => response.json())
.do(val => this.spinner = true)
.subscribe(
data => {
this.dataStore.meetingList = data;
this.meetingListObserver.next(this.dataStore.meetingList);
},
err => (...),
() => {
this.spinner = false;
subscription.unsubscribe();
})
);
}
Edit
If you want to use the spinner within the component and not the service. You could use a dedicated observable / subject, as described below:
spinner$: Subject<boolean> = new Subject();
spinner: boolean = false;
getList() {
var subscription = this.progressService.subscribe(event => {
if (!this.spinner) {
this.spinner = true;
this.spinner$.next(this.spinner); // <-------
}
});
this._http.get('../fake-data/someFile.json')
.map(response => response.json())
.do(val => this.spinner = true)
.subscribe(
data => {
this.dataStore.meetingList = data;
this.meetingListObserver.next(this.dataStore.meetingList);
},
err => (...),
() => {
this.spinner = false;
this.spinner$.next(this.spinner); // <-------
subscription.unsubscribe();
})
);
}
The component can subscribe on spinner$
to be notified of changes:
@Component({
(...)
})
export class SomeCOmponent {
constructor(private meetingService:MeetingService) {
this.meetingService.spinner$.subscribe((spinner) {
this.isLoaderEnabled = spinner;
});
}
}