0

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

2 Answers 2

2

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));
      });
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

This was very helpful, Thanks for the solution.
Glad to hear that
1

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.

2 Comments

Thanks for the explanation, this helped.
@GauthamK Sure. No Problem ^^

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.