cbloss793
cbloss793

Reputation: 1649

Angular subscribe. Can't get to data

UPDATE How I managed to do it is below (scroll to my answer or here's the link): https://stackoverflow.com/a/55013081/1729405

I'm trying to build a APIService in Angular 7. I'm using subscribe to push to an array which I can't access through another service.

Here's the api service method:

  getResponse(url):Observable<any> {
    return this.http.post(url, '', {responseType: 'text'});
  }

  getAll() {
      this.getResponse(this.todayApiUrl).subscribe(
        (response) => {
          this.data.push(response);
        });

      return this.data;
  }

Here's how I'm trying to call it in the secondary service:

export class AdsHealthService {
  today = this.callResponseApiService.getAll();


  constructor(private callResponseApiService: CallResponseApiService) { }

  getHealthValue(interval, type) {
    let obj = this.today;
    console.log(obj);
  }
}

In the attached image is what I get when I console.log() the response. It looks like an array but when I try to access the first element, I get an undefined message. What am I doing wrong?? enter image description here

Upvotes: 3

Views: 11636

Answers (4)

mayank arora
mayank arora

Reputation: 71

you can do it like this:

In your app-component:

public getDataFromService() {
  this._api.getData(this);
}


public setData(data: any){
 this.data=data;
}

In your service.ts:

public getData(obj: appComponentModel){
    this.http.get(url).subscribe(res => obj.setData(res));
}

its not exactly in the same format as your question but is easy one to understand by anyone.

Upvotes: 0

cbloss793
cbloss793

Reputation: 1649

In your service you would need the following:

  async getResponse(url) {
    return await this.http.post(url, '', {responseType: 'text'}).toPromise();
  }

  async getAll(url) {
    return await this.getResponse(url);
  }

In another service/component, you can retrieve the promise like below. To ensure that you're getting a promise back, you'd need to use a try catch block.

  async getToday() {
    try {
      let today = await this.yourServiceName.getAll(this.todayApiUrl);
      return today;
    } catch(e) {
        console.log(e);
    }
  }

then call:

let data = this.yourServiceName.getToday();
this.data.then((res) => {
// do stuff with 'res' here.
}

There isn't a way to save the value outside a then scope. To avoid hitting the API multiple times, I set up a cache service so that you can store/retrieve from cache when necessary. Here's the link to the article that I referenced for caching: https://hackernoon.com/angular-simple-in-memory-cache-service-on-the-ui-with-rxjs-77f167387e39

Here's what you can do:

  if (!this.cacheService.has('some key')) {
    let data = this.yourServiceName.init();
    this.cacheService.set('some key', data)
  } else {
    let cache = this.cacheService.get('data');
    // do stuff here.
  }

Hope that helps!

Upvotes: 1

joka00
joka00

Reputation: 2537

This happens because the http.post is asynchronous, you can make it synchronous by making the getResponse() async, transforming the Observable to Promise by .toPromise() and adding await before the http.post since that the getResponse() will not return Observable but raw data so the .subscribe() is no more necessary.

  async getResponse(url) {
    return await this.http.post(url, '', {responseType: 'text'}).toPromise();
  }

  async getAll() {
    this.data = await this.getResponse('some url');
    return this.data
  }
  async some() {
    const data = await this.getAll();
    console.log(data);
    console.log(this.data);
  }

Upvotes: 5

Aniruddha Das
Aniruddha Das

Reputation: 21688

You are not getting data or data as null or undefined because your rest endpoint will return data in the future but your return statement is returned immediately.

Below are the ways you can solve this

  • use async pipe in template and .map in the service
  • get the data when ready in your component by using map

below are code

  // one method is fine to return data from rest endpoint
  getAll(url):Observable<any> {
     return this.http.post(url, '', {responseType: 'text'});
   }

In you component class

export class AdsHealthService {

  constructor(private callResponseApiService: CallResponseApiService) {
     this.callResponseApiService.getAll().subscribe( (today) => {
       let obj = today;
       console.log(obj);
     });
  }

 rawdata = this.callResponseApiService.getAll();


}

Incase you directly show the data in template you can do that using async pipe.

<div>{{rawdata | async}}</div>

Upvotes: 0

Related Questions