Kay
Kay

Reputation: 324

Data not returning correctly

I am new to typeScript and Angular8

I have the following code that is to get data from a web service. Currently, it returns null but if I add console.log(this.service_type) to the line before the end of the if (user.status == 200) { block, I get the right data, how do I return the correct data

what am I not doing or doing wrong?

import { User } from '../_models/user';
import { Router } from '@angular/router';
import { ApiService } from './api.service';
import { ServiceType, Donations, Betting, Topup } from '../_models/data';


@Injectable({
    providedIn: 'root'
})

export class CheckService {
  constructor(
      private apiService: ApiService,
      private router: Router
  ) {}

  service_type: ServiceType = null;
  donations: Donations = null;
  betting: Betting = null;
  services: Topup = null;

  getReward() {
    this.apiService.getRewardServices().subscribe(
      user => {
        if (user.status == 200) {
          this.service_type = user.data.service_type;
          this.donations = user.data.donations;
          this.betting = user.data.betting;
          this.services = user.data.services;
        }
      }
    );
    return {service_type: this.service_type, donations: this.donations, betting: this.betting, services: this.services}
  }
}```

Upvotes: 0

Views: 41

Answers (2)

Zepa
Zepa

Reputation: 142

When the getRewards() method is called, the following things happen:

  1. The subscription to an observable is created.
    In the subscription you are passing an lambda function, which is called only, when the data from that stream comes.
  2. Returning the object
    When you are returning the object, the data from the stream has not come yet, so the values are still nulls.

What you can do, instead of subscribing to data in the method, return observable object and use it with async pipe.

Example

Service:

export class CheckService {
  constructor(
      private apiService: ApiService,
      private router: Router
  ) {}

  rewardObject$: Observable<any>;

  getReward() {
    this.rewardObject = this.apiService.getRewardServices().pipe(map(user => {
        if (user.status == 200) {
          return {
              service_type: user.data.service_type,
              donations: user.data.donations,
              betting: user.data.betting,
              services: user.data.services,
          };

          return null;
        }
    }));
  }
}

Template:

<ng-container *ngIf="(rewardObject$ | async) as reward">
    <span>{{reward.service_type}}</span>
</ng-container>

Upvotes: 1

MrMikimn
MrMikimn

Reputation: 851

You are hitting a road-block where most developers get stuck when first being introduced to the concept of asynchronous programming and reactive programming. You have some method, getRewardServices, which returns some Observable, which your service subscribes to, and performs the callback for each element this observable emits (you can read more here). The key problem is in this line:

return {service_type: this.service_type, donations: this.donations, betting: this.betting, services: this.services}

which can be executed before the observable emits a user object. The proper way to tackle this would be to map the observable into the object you want to return, and return the observable itself. It will be the responsibility of the outer service/component to unwrap the observable and handle the asynchronous event. Something like this:

getReward(): Observable<any> {
  return this.apiService.getRewardServices().pipe(
    map(user => {
      if (user.status == 200) {
        this.service_type = user.data.service_type;
        this.donations = user.data.donations;
        this.betting = user.data.betting;
        this.services = user.data.services;
        return {service_type: this.service_type, donations: this.donations, betting: this.betting, services: this.services}
      }
      return some_other_error_value;
      });
}

Upvotes: 1

Related Questions