简体   繁体   中英

How to handle async HTTP calls in Angular 8?

So I am new to Angular TypeScript and I have a problem.

So I have two files here, one is my component file with the function I use on Screen, and second one is HTTP service file where I make calls to a server.

Current my code structure is,

UserProfileComponent.ts

import { Component, OnInit } from '@angular/core';
import { UserService } from 'src/app/services/user.service';

@Component({
  selector: 'app-userprofile',
  templateUrl: './userprofile.component.html',
  styleUrls: ['./userprofile.component.scss']
})
export class UserprofileComponent implements OnInit {

  dataObj: any;

  constructor(private userService: UserService) {
    this.dataObj = this.userService.testCall();
    console.log('dataObj-> ' + JSON.stringify(this.dataObj));
  }

  ngOnInit() {
  }

}

and user.service.ts where I have this call

  testCall(): any{
    let responseObj: any;
    this.http.get(`${this.baseUrl}/users`).subscribe((data) => {
      console.log('responseObj-> '+JSON.stringify(data));
      responseObj = data;
    });
    return responseObj;
  }

So this issue for me is to handle the async call, the console.log('dataObj-> ' + JSON.stringify(this.dataObj)) does not wait for the service call to end and thus prints undefined .

I know this is the working but how do I handle this programatically?

I want the response data before I proceed to the next line.

Angular CLI: 8.3.25, Node: 12.16.1, OS: win32 x64, Angular: 8.2.14

The problem is that you do subscribe in your service, but instead you should do it in your component and return Observable from service.

So the final code should look like:

testCall(): Observable<UserType[]> {
  //I suppose you return Array of Users
  return this.http.get(`${this.baseUrl}/users`);
}

and component

export class UserprofileComponent implements OnInit {
  dataObj: UserType[];

  constructor(private userService: UserService) {        
  }

  ngOnInit() {
    this.userService.testCall()
      .subscribe((response: UserType[]) => {
        dataObj = response;
        console.log('dataObj-> ' + JSON.stringify(this.dataObj));
      });
  }
}

As @Yury explained, you need to get the subscription to the component level from the service level.

To make it even better what you can do is, Create an API service like the following:

api.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError, timeout, retry } from 'rxjs/operators';
import { CookieService } from 'ngx-cookie';
import { SERVER } from './static/static.json';

@Injectable({
    providedIn: 'root'
})


export class ApiService {
    user: Observable<any>;
    headers: HttpHeaders;

    constructor(
        private http: HttpClient,
        private cookieService: CookieService
    ) { }
    get(url: string, options?: any) {
        let key = SERVER.api + url;
        this.headers = new HttpHeaders();
        if(typeof options == 'string' && options != " "){
            this.headers = new HttpHeaders().append('Authorization', options);
        }
        return this.http.get(key, {headers: this.headers, withCredentials: false})
        .pipe(
            timeout(15000),
            retry(5),
            catchError(err => throwError(err))
        )
    }
    post(url: string, data: any, options?: any) {
        let key = SERVER.api + url;
        this.headers= new HttpHeaders();

        if(typeof options == 'string' && options != " "){
            this.headers = new HttpHeaders().append('Authorization', options);
        }

        return this.http.post<any>(key , data, {headers: this.headers, withCredentials: false})
        .pipe(
            catchError(err => throwError(err))
        );
    }

    put(url: string, data: any, options?: any) {
        let key = SERVER.api + url;
        this.headers= new HttpHeaders();

        if(typeof options == 'string' && options != " "){
            this.headers = new HttpHeaders().append('Authorization', options);
        }

        return this.http.put<any>(key , data, {headers: this.headers, withCredentials: false})
        .pipe(
            catchError(err => throwError(err))
        );
    }

    delete(url: string, options?: any) {
        let key = SERVER.api + url;
        this.headers= new HttpHeaders();

        if(typeof options == 'string' && options != " "){
            this.headers = new HttpHeaders().append('Authorization', options);
        }

        return this.http.delete<any>(key, {headers: this.headers, withCredentials: false})
        .pipe(
            catchError(err => throwError(err))
        );
    }

}

Then create a Module level service,

abs.service.ts

import { Injectable } from '@angular/core';
import { ApiService } from './shared/api.service';
import { AuthService } from './shared/auth.service';
@Injectable({
    providedIn: 'root'
})
export class ABSService {

    constructor(
        private _API: ApiService,
        private _AUTH: AuthService
    ){}
    getUsers(option?) {
        let url = '/users';
        let token;
        if(option){
            url = url + "?" + option;
        }
        if(this._AUTH.loginCheck()){
            token = this._AUTH.getCookie();
        }
        return this._API.get(url, token);
    }

    postUsers(data) {
        let url = '/users';
        let token;
        if(this._AUTH.loginCheck()){
            token = this._AUTH.getCookie();
        }
        return this._API.post(url,data, token);
    }
}

Then you can use this module-level service in the module level component like this:

abs.component.ts

import { Component, OnInit } from '@angular/core';
import { ABSService } from './abs.service';

@Component({
    selector: 'app-abs',
    templateUrl: './abs.component.html',
    styleUrls: ['./abs.component.css']
})

export class ABSComponent implements OnInit {
    constructor(
        private _API: ABSService
    ) {}
    ngOnInit(){
        this._API.getUsers().subscribe(
            (data:any)=>{
                // something related to data
                this.dataObj = data;
                console.log('dataObj-> ' + JSON.stringify(this.dataObj));
            },
            (err)=>{
                // something related to error
            }
        )
    }
}

I prefer to keep HTTP module separate since the last time when they changed the HTTP module with HttpClient module, I had to go through a lot of work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM