'Subscription of observable returns undefined

I use a service to fill my observable with data from the backend. The backend is delievering the correct data. Now I want to take the values of the observable and build a piechart.

The part of the Code looks like this:

this.dataSet = this.dataService.getData(this.id);
this.dataSet.subscribe(
x => this.rightData = x.rightCount,
x => this.wrongData = x.wrongCount,
);
console.log('First value: '+ this.rightData);
console.log('Second value: '+ this.wrongData);
this.pieChartData = [this.rightData, this.wrongData];

It doesn't work and the console output is:

First Value: undefined
Second Value: undefined

But when I change the code to the following, the console log shows the right data:

this.dataSet = this.dataService.getData(this.id);
this.dataSet.subscribe( 
x => console.log(x.rightCount),
x => console.log(x,wrongCount),
);

Output:

3
7

Additional code:

export interface Counter {
  rightCount: number;
  wrongCount: number;
}

dataSet: Observable<Counter> = of();

The service looks like:

getData(id: number): Observable<Counter> {
    return this.http.get<Counter>(`/backend/getData?id=${id}`);
  }

The firefox log shows me, the backend returns:

{"rightCount":3,"wrongCount":7}

Do you have an Idea where I make a mistake?



Solution 1:[1]

this behaviour is normal since your code (subscribe) runs asynchronously. It would be the same as:

let test;
setTimeout(() => {this.test = "hello"}, 1000);
console.log(test);

the code above would print undifined right? doing subscribe() is similar to a setTimeoutsince both code runs asynchronously.

also if you would do:

this.dataSet.subscribe(
x => console.log('test1')
);
console.log('test2');

the output would be: test2 test1 because the code inside subscribe asynchronously

the correct code in your case would be:

this.dataService.getData(this.id).subscribe(
  x => {
    this.rightData = x.rightCount;
    console.log('First value: '+ this.rightData);
    // this.wrongData is undefined here
    this.pieChartData = [this.rightData, this.wrongData];
  },
  err => {
    this.wrongData = x.wrongCount;
    console.log('Second value: '+ this.wrongData);
    // this.rightData is undefined here
    this.pieChartData = [this.rightData, this.wrongData];
  }
);

please note that the Second value / wrongData will only occurr if an error is thrown in this.dataService.getData

Solution 2:[2]

You can encapsulate the final manipulation inside the "finaly" in subscribe.

something like this

this.dataSet = this.dataService.getData(this.id);
this.dataSet.subscribe(
  x => (this.rightData = x.rightCount),
  x => (this.wrongData = x.wrongCount),
  () => {
    console.log('First value: ' + this.rightData)
    console.log('Second value: ' + this.wrongData)
    this.pieChartData = [this.rightData, this.wrongData]
  }
);

Or just

this.dataService.getData(this.id).subscribe(
  x => (this.rightData = x.rightCount),
  x => (this.wrongData = x.wrongCount),
  () => {
    console.log('First value: ' + this.rightData)
    console.log('Second value: ' + this.wrongData)
    this.pieChartData = [this.rightData, this.wrongData]
  }
);

Note that the "finally" doesn't receive any parameters, it only serves to do manipulations after receiving success or error from the observable

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Zerotwelve
Solution 2 André Oneti