RRB
RRB

Reputation: 2116

undefined value after subscribing to endpoint

I am getting an undefined value when trying to subscribe to a response that it being passed through by a service file

here is my code

service.ts

getUserDetails(): Observable<GetUserByIdModel> {
  const token = this._storeService.getStoredData().id_token;
  const candidateId = this._storeService.getStoredData().profile.CandidateId;
  const headers = new HttpHeaders()
    .set('Authorization', `Bearer ${token}`)
    .set('Content-Type', 'application/json');
  const options = { headers: headers };
  const url = `${this.candidateUrl}/Get/${candidateId}`;
  this._http.get<GetUserByIdModel>(url, options).subscribe((resp) => {
    this.userDetails = {
      firstname: resp.firstname,
      lastname: resp.lastname,
      nationalityId: resp.nationalityId,
      identityTypeId: resp.identityTypeId,
      identityValue: resp.identityValue,
      titleId: resp.titleId,
      genderId: resp.genderId,
      candidateContactChannels: [
        { type: 1, value: resp.candidateContactChannels[0].value },
        { type: 2, value: resp.candidateContactChannels[1].value }
      ],
    };
    console.log(this.userDetails);
  })

  return new Observable((observer) => {
    observer.next(this.userDetails);
    observer.complete();
  });
}

component.ts

ngOnInit() {
  this._loader.start();
  this._profileService.getUserDetails().subscribe((resp) => {
    this.user = resp;
    console.log(this.user);
    this._loader.stop();
  }, (error) => {
    this._loader.stop();
    this._errorService.openErrorPopup('Failed to get user data.');
  });
}

The undefined value I am referring to is in the component.ts file console.log(this.user); My console.log in the service is showing the populated data correctly

Upvotes: 0

Views: 338

Answers (2)

Bastien verschaete
Bastien verschaete

Reputation: 445

You are using RxJs wrong. In your service you already have the observable that you can return to your controller, why would you subscribe in your service and then create and return a new observable?

In your case this means something like this:

service.ts

getUserDetails(): Observable<GetUserByIdModel> {
  const token = this._storeService.getStoredData().id_token;
  const candidateId = this._storeService.getStoredData().profile.CandidateId;
  const headers = new HttpHeaders()
    .set('Authorization', `Bearer ${token}`)
    .set('Content-Type', 'application/json');
  const options = { headers: headers };
  const url = `${this.candidateUrl}/Get/${candidateId}`;

  return this._http.get<GetUserByIdModel>(url, options).pipe(
    map((resp) => 
      {
        firstname: resp.firstname,
        lastname: resp.lastname,
        nationalityId: resp.nationalityId,
        identityTypeId: resp.identityTypeId,
        identityValue: resp.identityValue,
        titleId: resp.titleId,
        genderId: resp.genderId,
        candidateContactChannels: [
          { type: 1, value: resp.candidateContactChannels[0].value },
          { type: 2, value: resp.candidateContactChannels[1].value }
        ],
      };
    })
  );
}

So instead of subscribing to the observable in your service, you let the response from your server 'flow' through a pipe and map everything that 'flows' through there to another object, to which you can subscribe in your controller.

In this case though I see that you map the response you get from the API to the exact same object, which means you can actually do this:

service.ts

getUserDetails(): Observable<GetUserByIdModel> {
  const token = this._storeService.getStoredData().id_token;
  const candidateId = this._storeService.getStoredData().profile.CandidateId;
  const headers = new HttpHeaders()
    .set('Authorization', `Bearer ${token}`)
    .set('Content-Type', 'application/json');
  const options = { headers: headers };
  const url = `${this.candidateUrl}/Get/${candidateId}`;

  return this._http.get<GetUserByIdModel>(url, options);
}

Your component.ts class can stay the same.

Upvotes: 1

schoolcoder
schoolcoder

Reputation: 1654

this.http.get() is an asynchronous call.Before the call is over, you are returning the observable.

instead, you just define and pass the callback function,

ngOnInit() {
  this._loader.start();
  this._profileService.getUserDetails((resp) => {
    this.user = resp;
    console.log(this.user);
    this._loader.stop()
  }, (err) => {
    this._loader.stop();
    this._errorService.openErrorPopup('Failed to get user data.');
  })
}

In service,

getUserDetails(callback, err): void {
  const token = this._storeService.getStoredData().id_token;
  const candidateId = this._storeService.getStoredData().profile.CandidateId;
  const headers = new HttpHeaders()
    .set('Authorization', `Bearer ${token}`)
    .set('Content-Type', 'application/json');
  const options = { headers: headers };
  const url = `${this.candidateUrl}/Get/${candidateId}`;
  this._http.get<GetUserByIdModel>(url, options).subscribe((resp) => {
    this.userDetails = {
      firstname: resp.firstname,
      lastname: resp.lastname,
      nationalityId: resp.nationalityId,
      identityTypeId: resp.identityTypeId,
      identityValue: resp.identityValue,
      titleId: resp.titleId,
      genderId: resp.genderId,
      candidateContactChannels: [
        { type: 1, value: resp.candidateContactChannels[0].value },
        { type: 2, value: resp.candidateContactChannels[1].value }
      ],
    };
    callback(this.userDetails);
  }, () => {
     err();
  })
}

Upvotes: 1

Related Questions