Extending HTTP works well - in our project we also wanted explicit control of the 'loader' aka spinner for some scenarios. So we have a SpinnerService in our Core module that is available to all components.
@Injectable()
export class SpinnerService {
private spinnerStateSource = new Subject<SpinnerState>();
spinnerState$ = this.spinnerStateSource.asObservable();
private defaultMessage: string = 'Loading...';
show(message?: string) {
let msg = this.defaultMessage as string;
if (message) {
msg = message;
}
this.spinnerStateSource.next({ showing: true, message: msg });
}
hide() {
this.spinnerStateSource.next({ showing: false, message: '' });
}
spin(obs: Observable<any>, message?: string): Observable<any> {
this.show(message);
return obs.finally(() => this.hide());
}
}
class SpinnerState {
showing: boolean;
message: string;
}
A component in the main module subscribes to the service to show/hide the actual spinner UI (EDIT: just like in @Gunter's answer), and other components can (via the service) tell the spinner to show/hide.
An example where we use that is if a component has to make multiple HTTP calls to e.g. get some reference data, then we want the spinner to show til all those calls are done. So we call the spin
function with the action we are waiting on
e.g. in the consuming component:
this.spinnerService.spin(
Observable.forkJoin(
this.refDataService.getRefDataList('statusTypes'),
this.refDataService.getRefDataList('itemTypes')
)
).subscribe(result => {
this.statusTypes = result[0];
this.itemTypes = result[1];
});