After creating a loading spinner component for my angular 4 application to display during AJAX calls, I encountered an issue when trying to implement it with a subscription to a BehaviorSubject.
This question is similar to how to show a spinner until data is received from the server in angular2, but it's not identical as I intend to use a reusable component. I also came across Angular 2 + RxJS BehaviorSubject subscribe call not working, although I'm struggling to identify any differences between my code and the accepted answer. Could there be something I missed?
The approach I followed is based on this tutorial:
Below are snippets of my code:
app.modules.ts
import {AppComponent} from './app.component';
import {AppRoutingModule} from './app-routing.module';
import {SomeComponent} from './some.component';
import {LoaderComponent} from './loader/loader.component';
import {LoaderService} from './loader/loader.service';
@NgModule({
declarations: [
AppComponent,
LoaderComponent,
SomeComponent
],
imports: [
BrowserModule,
NoopAnimationsModule,
AppRoutingModule
],
providers: [
LoaderService
],
bootstrap: [AppComponent]
})
export class AppModule {
}
app.component.html
<router-outlet></router-outlet>
<app-loader></app-loader>
loader.component.html
<div class="loader" *ngIf="isLoading"></div>
loader.component.ts
import {Component, OnInit} from '@angular/core';
import {LoaderService} from './loader.service';
@Component({
selector: 'app-loader',
templateUrl: 'loader.component.html',
providers: [LoaderService]
})
export class LoaderComponent implements OnInit {
isLoading: boolean;
constructor(private loaderService: LoaderService) {
}
ngOnInit() {
this.loaderService.status.subscribe((val: boolean) => {
this.isLoading = val;
});
}
}
loader.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class LoaderService {
public status: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
display(value: boolean) {
console.log('LoaderService.display ' + value);
this.status.next(value);
}
}
A method in some service that does an AJAX call
constructor(private http: Http, private loaderService: LoaderService) {
}
getSomeStuff(): Observable<SomeItem[]> {
// show the loading spinner
this.loaderService.display(true);
const content = this.http.get(this.apiUrl)
.map(this.extractData);
content.subscribe(
() => {
// hide the loading spinner
this.loaderService.display(false);
}
);
return content;
}
The main issue is that the loader never appears because the isLoading
property is never set to true
. The console output shows:
LoaderComponent subscription false
LoaderService.display true
LoaderService.display false
According to how BehaviorSubject should function, the subscription to LoaderService.status
within loader.component.ts
ought to trigger whenever the status changes. Why is it not working as expected? What am I missing here?