2

Im trying to use the data from an api call but the data is not returned when I'm trying to access it so im getting undefined. Heres the code:

API Service:

public addBusiness(businessObject)
{

    // Testing endpoint dor fake endpoint
    let endPoint = '/business';

    // let endPoint = this.baseUrl+`/business`;

    let content = {businessObject: businessObject};
    let headers = new Headers({ 'Content-Type': 'application/json', 'Accept': 'application/json' });
    let options = new RequestOptions({ headers: headers });
    let body = JSON.stringify(content);

    return this.http.post(endPoint, body, options )
        .map(res => res.json());

}

Component:

this.BusinessApiService.addBusiness(businessObject).subscribe(res => {
      // Check for an success response if there is do:
      if (res.request.status === 'success') {
          console.log('%c addBusiness API call was a success', 'color: green; font-weight: bold;');
          console.log(res);

          let currentQuoteObj = {
              businessId: res.data.businessId,
              applicantIds: []
          };

          this.quoteHandler.saveCurrentQuote(currentQuoteObj);

          let businessId = this.quoteHandler.currentQuote['businessId'];

          let that = this;

          this.applicants.value.forEach(function(applicant) {
              // console.log(applicant);

              console.log(businessId);

              that.BusinessApiService.addApplicant(applicant, businessId).subscribe(res => {
                  if (res.request.status === 'success') {
                      let appicantId = res.data.applicantId;

                      that.quoteHandler.addApplicanToCurrentQuote(appicantId);
                  }
                  else {
                      // Todo add error handling
                      console.log('ITS BROKE');
                  }
              });
          });


          console.log('Current Quote object:');
          console.log(this.quoteHandler.currentQuote);

          console.log('Current Uncompleted Applicant object:');
          console.log(this.quoteHandler.currentUncompletedApplicants);
      }
      // If there is an error handle it here
      else {
          // Todo add error handling
          console.log('%c addBusiness API call was a fail', 'color: red; font-weight: bold;');
          // console.log(res);
      }
  });

The add applicant api is basically the same as the add business api call. How would i get this to work so it does what i want it to do but it will not just get undefined on the businessId and appicantId. Thanks!

EDIT: json im expecting back from API:

{
  "request" : {
    "status" : "success",
    "action" : "Business Created"
  },
  "data":{
    "businessId" : 1021
  }
}
Tom Rouse
  • 51
  • 9
  • `http.post()` returns a `Promise`, but you're trying to call `.map()` on it. –  Aug 25 '17 at 13:42
  • @ChrisG Do i know what i should be doing instead? – Tom Rouse Aug 25 '17 at 13:43
  • @Chris Uh no, it returns an Observable. It's Angular/RxJS we're talking about. – Jeremy Thille Aug 25 '17 at 13:44
  • @JeremyThille I think its because the Observable is not retuned when the rest of the code is ran meaning theres no data to access till after if that makes sense? – Tom Rouse Aug 25 '17 at 13:45
  • @JeremyThille I realize that, but I accidentally checked the docs for Angular 1. –  Aug 25 '17 at 13:46
  • Can you post the json you are expecting to get back from the api? – LLai Aug 25 '17 at 13:49
  • what is the answer of your backend when you send a request? – Jota.Toledo Aug 25 '17 at 13:51
  • I'm probably digging myself an even deeper hole here, but isn't calling `.map` still wrong? If it's an `Observable`, shouldn't we be calling `.subscribe()` on it and pass a handler? I.e. isn't this basically once again a duplicate of the tired old https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call –  Aug 25 '17 at 13:52
  • @LLai thats added – Tom Rouse Aug 25 '17 at 13:53
  • @Jota.Toledo i get the repose fine and its what im expecting but im getting undefined on businessId as thats using the res to assign the data but im thinking the http call is still not returned the data when the code setting the value is ran as its running asynchronously – Tom Rouse Aug 25 '17 at 13:55
  • @ChrisG : applying `map` would return an Observable, and you would indeed still need to `subscribe` on it, for the call to be made ! Nevertheless, it's not wrong per se. Expecting the request to be fired by using `map` only *is* wrong however. – Pac0 Aug 25 '17 at 13:58

1 Answers1

1

It's undefined because you're not waiting for all BusinessApiService.addApplicant Observables to emit a value before accessing the resolved data. You should make use of RxJs operators like forkJoin, to wait for all requests.

The forkJoin operator is basically the rx equivalent of Promise.all for more check out the docs.

Like:

this.BusinessApiService.addBusiness(businessObject).switchMap(res => {
  if (res.request.status !== 'success') {
    // do error handling here
  }

  let businessId = res.data.businessId;
  this.quoteHandler.saveCurrentQuote({ 
    businessId,
    applicantIds: []
  });

  return Observable.forkJoin(this.applicants.value.map(applicant => {
    return this.BusinessApiService.addApplicant(applicant, businessId);
  }));
}).subscribe(applicantResponses => {
    // do something with your applicant responses
});
cyr_x
  • 13,987
  • 2
  • 32
  • 46
  • Im getting: property 'switchMap' does not exist on type Observable and can not find name 'Observable' – Tom Rouse Aug 25 '17 at 14:03
  • I think im just not sure how to correctly implement this – Tom Rouse Aug 25 '17 at 14:04
  • Did you add the operators via `import 'rxjs/add/operator/switchMap';` and `import 'rxjs/add/operator/forkJoin';`? – cyr_x Aug 25 '17 at 14:05
  • Yeah i forgot that, but im still getting can not find name 'Observable' after adding the imports – Tom Rouse Aug 25 '17 at 14:07
  • Did you import `Observable` from `rxjs/Observable` ? – cyr_x Aug 25 '17 at 14:08
  • I fixed it with import {Observable} from 'rxjs/Rx'; but still not working getting more errors: Error: Can't resolve 'rxjs/add/operator/forkJoin' in 'FILE/LOCATION' – Tom Rouse Aug 25 '17 at 14:16
  • Not really, the error "can not find name 'Observable'" indicates that you didn't write `import { Observable } from 'rxjs/Observable';` – cyr_x Aug 25 '17 at 14:16
  • I skipped some parts of your code just to give an example how to use `forkJoin` maybe you forgot to add your parts at the right position? – cyr_x Aug 25 '17 at 14:19
  • I've added your parts to my answer. What are the errors you're getting? – cyr_x Aug 25 '17 at 14:24
  • Im getting: Module not found: Error: Can't resolve 'rxjs/add/operator/forkJoin' – Tom Rouse Aug 25 '17 at 14:26
  • 1
    @TomRouse the import is under observable instead of operator import 'rxjs/add/observable/forkJoin'; – LLai Aug 25 '17 at 14:28
  • Yeah sry my bad, it's indeed under observable, thank's for pointing this out. – cyr_x Aug 25 '17 at 14:29
  • It seems to be working great thanks very much!, one question tho how do i add the for each loop back like i had it before? – Tom Rouse Aug 25 '17 at 14:40
  • If you want to loop through the applicant responses data just do `applicatnResponses.forEach` inside the `subscribe`. – cyr_x Aug 25 '17 at 14:42
  • @cyrix ok thanks, any chance you could explain how this works im a bit confused? – Tom Rouse Aug 25 '17 at 14:42
  • As is said in my answer `forkJoin` is like `Promise.all` it waits for all `Observables` inside it's input array and returns an array with the emitted values. – cyr_x Aug 25 '17 at 14:43
  • `switchMap` is basically a "switch", you're switching from one stream to another, while you can use the data from the previous one. For a detailed explanation read: http://blog.angular-university.io/rxjs-switchmap-operator/ – cyr_x Aug 25 '17 at 14:48