What i am trying to do is:
I want to use the spinner whenever a http request accurs. In other words i want user to see a loading screen whenever a http request happens in my app.component.
My spinner.component and spinner-service files are same with the answer in this question.
And my app.component's component is
@Component({
selector: 'todoApi',
template: `
<div class="foo">
<spinner-component></spinner-component>
<h1>Internship Project</h1>
<a [routerLink]="['Dashboard']">Dashboard</a>
<a [routerLink]="['Tasks']">List</a>
<router-outlet></router-outlet>
<div>
`,
directives: [ROUTER_DIRECTIVES,SpinnerComponent],
providers: [
ROUTER_PROVIDERS,
]
})
@RouteConfig([
{
path: '/dashboard',
name: 'Dashboard',
component: DashboardComponent,
useAsDefault: true
},{
path: '/tasks',
name: 'Tasks',
component: TaskComponent
},{
path: '/detail/:id',
name: 'TaskDetail',
component: TaskDetailComponent
},
])
To conclue , whenever a http request occurs in one of these routes, i want to show the spinner to user. I know this has been a bad question , but i am new to angular 2 and i would realy be grateful if anyone could help me with that.
Thanks alot!
Edit!:
Solution with Günther's answer:
I wrapped my http
and spinner-service
into a HttpClient
component and used it instead of regular http module. Here is my HttpClient
component:
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { SpinnerService} from './spinner-service';
@Injectable()
export class HttpClient {
constructor(
private http: Http,
public spinner: SpinnerService
){
}
createAuthorizationHeader(headers:Headers) {
headers.append('Authorization', 'Basic ' + btoa('username:password'));
}
get(url) {
this.spinner.start();
let headers = new Headers();
this.createAuthorizationHeader(headers);
return this.http.get(url, { headers: headers }).do(data=> {this.spinner.stop()});
}
post(url, data) {
this.spinner.start();
let headers = new Headers();
this.createAuthorizationHeader(headers);
return this.http.post(url, data, { headers: headers }).do(data=> {this.spinner.stop()});
}
}
Use a service that is shared between Http
(there are answers already how about wrapping Http
in your own class) and the <spinner-component>
.
See also https://angular.io/docs/ts/latest/cookbook/component-communication.html
In the shared service maintain a counter of started (increase) and completed/failed HTTP requests and notify the <spinner-component>
every time when the counter changes from 0
to >0
or from >0
to 0
to enable or disable itself.
Thanks for your answer Günter Zöchbauer's, An example which I built based on my needs. I did not use an HTTP wrapper which would be easier to use, however, this example works with multiple services calls based on your counter suggestion. Hope it helps someone :)
Create the Loader service.
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class LoaderService {
public loaderCounter: BehaviorSubject<number> = new BehaviorSubject<number>(0);
displayLoader(value: boolean) {
let counter = value ? this.loaderCounter.value + 1 : this.loaderCounter.value - 1;
this.loaderCounter.next(counter);
}
}
Include the service within the providers of your maain module file (Ex: AppModule)
In your main component file (Ex: AppComponent), subscribe to the changes and reflect to the loader (in my case it's a seperate component).
//Imports
import { Subscription } from 'rxjs/Subscription';
import { LoaderService } from './core/loader.service';
..
@Component({
selector: 'my-app',
template: `
<div class="container-fluid content">
<router-outlet></router-outlet>
</div>
<spinner [visible]="displayLoader"></spinner>
`
})
export class AppComponent implements OnInit, OnDestroy {
displayLoader: boolean;
loaderSubscription: Subscription;
constructor(private loaderService: LoaderService) {}
ngOnInit() {
this.loaderSubscription = this.loaderService.loaderCounter.subscribe((counter: number) => {
this.displayLoader = counter != 0;
});
}
ngOnDestroy() {
this.loaderSubscription.unsubscribe();
}
}
Using the loader service:
import { LoaderService } from './core/loader.service';
..
export class SampleComponent implements OnInit {
constructor(private _service: SomeService, private loader: LoaderService) { }
ngOnInit() {
this.loader.displayLoader(true);
this._service.getBalance().subscribe(
response => ..do something..,
() => .. error..,
() => this.loader.displayLoader(false)
);
}
}
Just for the people who gets here from now on...
With this solution the spinner will not stop in case of error with the http request. Make sure you do the following:
...
return this.http.post(url, data, { headers: headers })
.do(data=> {this.spinner.stop()},
err=> {this.spinner.stop());
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With