Reputation: 105
I am trying to show a spinner using a observable which resolves to a boolean value using a async pipe in a template. The value of the observable is set in the service. I am not able to figure out whats going wrong. The observable value seems to resolve to undefined. Why this could be not working?
Here is the stackblitz created for the example.
Upvotes: 0
Views: 795
Reputation: 8443
It is undefined because we run setLoader
inside ngOnInit
where view is not ready. At that time, loading$
in service class is still undefined. When template renders it, definitely it is undefined.
I'd move the setLoader
to ngAfterViewInit
import { Component, VERSION, AfterViewInit } from '@angular/core'; // import AfterViewInit
import { MyService } from './my.service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit { // add AfterViewInit
constructor(public myservice: MyService) {
}
ngOnInit() {
}
ngAfterViewInit() {
this.myservice.setLoader(true); // move it here
}
}
Also I checked that there's a typo in the template, the original code uses myservice.loader$
but it is supposed to be myservice.loading$
.
<div *ngIf="myservice.loading$ | async">
Loading
</div>
Hope it helps
Upvotes: 1
Reputation: 71961
You should not use a Subject()
, or do the setLoader in ngAfterViewInit
, at the moment you do .next(true)
the template is not subscribed to it yet:
Solution 1:
export class AppComponent {
loading$: Observable<boolean>;
constructor(private myservice: MyService) {
this.loading$ = myservice.loading$;
}
ngAfterViewInit() {
this.myservice.setLoader(true);
}
}
Solution 2:
export class AppComponent {
loading$: Observable<boolean>;
constructor(private myservice: MyService) {
this.loading$ = myservice.loading$.pipe(
shareReplay(1)
);
}
ngOnInit() {
this.myservice.setLoader(true);
}
}
Solution 3:
private loadingSource = new ReplaySubject(1);
loading$ = this.loadingSource.asObservable();
constructor() { }
setLoader(isLoading: boolean) {
this.loadingSource.next(isLoading);
}
Upvotes: 1