0

I'm using ngOnInit in order to get a response from a Loopback API call. The property I initialize inside this scope can't be used outside the subscribe scope. I know this is a simple answer but I'm just not seeing it

private siteData: Kiosk;

  constructor(private dataService: DataService){} 

 ngOnInit(){
    this.dataService.getDataByID(this.dataService.getSiteID())
        .subscribe((data:Site) => { 
             this.siteData = data;
             console.log(this.siteData); // This outputs correctly 
    });
    console.log(this.siteData); // This is undefined
  }

  site: any[] = [{
    title: this.siteData.title, // this is undefined and throws error
  }];

I expect output to not be undefined and be the data that is in the response

Nakatax
  • 13
  • 6

5 Answers5

0

This is because observables are asynchronous. sideData isn't defined until after the assignment is made in the subscribe call – it's similar to a promise.

If you try to access the value set by a promise before a .then is called, then it will also be undefined. The way around this would be to use the tap operator to set it in a pipe, and then operate on it in other ways in the subscribe. Alternatively, you could use something like ngrx that will automatically update the to latest value.

wilsonhobbs
  • 941
  • 8
  • 18
  • To nitpick a little, observables aren't _inherently_ asynchronous. An `of("foo").subscribe(console.log)` will log before the next line is executed. – mbojko May 28 '19 at 16:00
0

I also want to point you towards developing a better understanding of the lifecycle hooks in Angular. You are setting your class property like this:

site: any[] = [{
    title: this.siteData.title, // this is undefined and throws error
  }];

This means, you are accessing this.sideData, which is only set in the ngOnInit hook that actually runs after the component has been initialised (constructed). Furthermore, you are only subscribing to the Observable in the lifecycle hook (OnInit), i.e. you are not actively assigning the result just yet, only after the observable emits a result. Your observable does not have to be asynchronous, but in your case most likely is.

Short story: You are getting errors, because you are trying to access a property of an object this.siteData, that is at that point of time undefined.

ErnieandBert
  • 91
  • 1
  • 1
  • 8
-1
console.log(this.siteData); // This is undefined

because this doesn't wait for this.dataService.getDataByID to finish use the one inside if you don't want it to be undefined

dota2pro
  • 7,220
  • 7
  • 44
  • 79
-1

You will need to initialize the variables inside the subscribe method with the values which you are doing already.

Now You can access them in the HTML once the request is completed. Make sure to add a check in the HTML i.e if siteData using *ngIf & then use those variables normally

Agam Banga
  • 2,708
  • 1
  • 11
  • 18
-1

fill your fields only when you get data like this:

private siteData: Kiosk;
site: any[];

  constructor(private dataService: DataService){} 

 ngOnInit(){
    this.dataService.getDataByID(this.dataService.getSiteID())
        .subscribe((data:Site) => { 
             this.siteData = data;
             site = [{title: data.title}];
    });
  }
GJCode
  • 1,959
  • 3
  • 13
  • 30