5

I trying to put a progress bar in my http call but some how i wont be able to make a sync HTTP call request instead its going in async fashion.

below is function for making http call

 public authenticationt2cHTTP(email, password) {
    console.log("authenticationt2cHTTP WITH HEADERS");
    const body = new HttpParams()
      .set('email', email)
      .set('password', password);
    const req = new HttpRequest('POST', 'http://192.168.0.135:8080/rest/auth/login', body, {
      reportProgress: true,
      headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
    });

    this.http.request(req).subscribe(event => {
      // Via this API, you get access to the raw event stream.
      // Look for upload progress events.
      if (event.type === HttpEventType.UploadProgress) {
        // This is an upload progress event. Compute and show the % done:
        const percentDone = Math.round(100 * event.loaded / event.total);
        console.log(`File is ${percentDone}% uploaded.`);
      } else if (event instanceof HttpResponse) {
        console.log('File is completely uploaded!');
      }
    });

  }

below is code which i am using in my component class for making a call and showload is temp variable for showing/hiding preloader of the page.

this.showLoader = false;
      var k = this.myhttpService.authenticationt2c(this.form.get("email").value, this.form.get("password").value);
      this.showLoader = true;
Feroz Siddiqui
  • 3,840
  • 6
  • 34
  • 69
  • 5
    You shouldn't even try to make it sync, rather learn how to properly use async. `this.showLoader = true;` is executed before the request to the server is completed. You need to return a stream or promise from `authentication2c` so that you can chain subsequent code to be executed when `authentication2c` is completed. Read up on async before you try anything else. You won't get anywhere in Angular without that knowledge. – Günter Zöchbauer Jan 05 '18 at 12:25
  • https://angular.io/guide/http i m using this guide but couldnt abe to figure out how to achieve this pls help me – Feroz Siddiqui Jan 05 '18 at 13:03

2 Answers2

2

As mentioned in comments, this is asynchronous, so while the request takes some time to execute,

this.showLoader = false;
// takes some time to execute
var k = this.myhttpService.authenticationt2c(...);
// executed while waiting for above code to execute
this.showLoader = true;

Instead, from your service, return an Observable and in component subscribe. Then inside the callback (subscribe) switch the boolean flag. I'd guess that you would want to actually switch the boolean flag showLoader to false after the request have been completed, so I switched them around below:

this.showLoader = true;
this.myhttpService.authenticationt2c(...)
  .subscribe(() => this.showLoader = false)

and from the service, as said, return an Observable, so use map instead of subscribe:

this.http.request(req).map(event => { ... })

Check these links for reading up on asynchronicity: How do I return the response from an Observable/http/async call in angular2? and How do I return the response from an asynchronous call?

AT82
  • 71,416
  • 24
  • 140
  • 167
1

I use the following http service wrapper to get access to different hooks like handleResponse, beforeRequest, afterResponse, onCatch & onSuccess.

The API services should consume the HttpInterceptor wrapper (which internally triggers the http call and gives access to above mentioned hooks).

Note how the loader logic is implemented in beforeRequest & afterResponse hooks.

import { Injectable } from "@angular/core";
import { XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Http, Headers } from "@angular/http";
import { Store } from "@ngrx/store";
import { Observable } from "rxjs/Rx";
import { Observer } from "rxjs/Observer";
import { Response as ApiResponse } from "../../models/base/response.model";
import { ToastModel } from "../../redux/app-reducers";
import { ReducerActions } from "../../redux/reducer-actions";

@Injectable()
export class HttpInterceptor extends Http {
    constructor(private _XHRBackend: XHRBackend,
        private _RequestOptions: RequestOptions,
        private _ToastStore: Store<ToastModel>,
        private _LoaderStore: Store<boolean>) {
        super(_XHRBackend, _RequestOptions);
    }

    public request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        return this.handleResponse(super.request(url, options));
    }

    public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        this.beforeRequest(url);
        return super.get(url, this.getRequestOptionArgs(options));
    }

    public post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
        this.beforeRequest(url, body);
        return super.post(url, body, this.getRequestOptionArgs(options));
    }

    public put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
        this.beforeRequest(url, body);
        return super.put(url, body, this.getRequestOptionArgs(options));
    }

    public delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
        this.beforeRequest(url);
        return super.delete(url, this.getRequestOptionArgs(options));
    }

    private getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
        if (options == null) {
            options = new RequestOptions();
        }
        if (options.headers == null) {
            options.headers = new Headers();
        }
        options.headers.append('Content-Type', 'application/json');

        return options;
    }

    private handleResponse(response: Observable<Response>): Observable<Response> {
        return response
            .catch(this.onCatch)
            .do(this.onSuccess.bind(this), this.onError.bind(this))
            .finally(this.afterResponse.bind(this));
    }

    private beforeRequest(url: string, body?: string): void {
        this._LoaderStore.dispatch({ type: ReducerActions.Loader.Set, payload: true });
    }

    private afterResponse(): void {
        this._LoaderStore.dispatch({ type: ReducerActions.Loader.Set, payload: false });
    }

    private onCatch(error: any, caught: Observable<Response>): Observable<Response> {
        console.log("interceptor catch called");
        return Observable.throw(error);
    }

    private onSuccess(res: Response): void {
        let response: ApiResponse<any> = res.json();
        if (!response.message) {
            return;
        }
        let toast: ToastModel = {
            text: response.message,
            duration: 5000,
            type: "success"
        };
        this._ToastStore.dispatch({ type: ReducerActions.Toast.Update, payload: toast });
    }

    private onError(error: any): void {
        let toast: ToastModel = {
            text: "Error occurred!",
            duration: 5000,
            type: "failure"
        };
        this._ToastStore.dispatch({ type: ReducerActions.Toast.Update, payload: toast });
    }
}

I hope this helps :)

planet_hunter
  • 3,866
  • 1
  • 26
  • 39