ozata
ozata

Reputation: 562

Angular 2 loader on each http request

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()});
  }
}

Upvotes: 9

Views: 16870

Answers (4)

Jamie Rees
Jamie Rees

Reputation: 8183

You could also use Pace.js

Would be pretty easy to add

<head>
  <script src="/pace/pace.js"></script>
  <link href="/pace/themes/pace-theme-barber-shop.css" rel="stylesheet" />
</head>

You can find the documentation here: http://github.hubspot.com/pace/

Upvotes: 0

Mark Cutajar
Mark Cutajar

Reputation: 340

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 :)

  1. 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);
        }
    }
    
  2. Include the service within the providers of your maain module file (Ex: AppModule)

  3. 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();
        }
    }
    
  4. 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)
            );
        }
    }
    

Upvotes: 4

Gabriel
Gabriel

Reputation: 412

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());
...

Upvotes: 1

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 658205

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.

Upvotes: 7

Related Questions