3

I want to return the events after the subscriber is called.

 getCalendarData(){
      var body = JSON.stringify({"cid": "etNG3V61LWS6Pzkeb_omuZGMVAOLd1_70tRQblVizWQ~",
      "seldt":"2018-09-18"}); 
      var headers = new HttpHeaders();
      headers.append('Content-Type', 'application/json');

      return this.httpClient.post(this.apiUrl, body, { headers: headers })

    }

The above code works perfectly. It also returns the JSON.

Now the problem is, when I call this method inside the getCalendarEvents(), I failed to return the events as the function is not void. So it should have a return type. So how will I pass events since subscribe is asynchronus.

 getCalendarEvents(): Array<CalendarEvent> {
         var listCal:any = []
         this.getCalendarData().subscribe((data: any) => {
          listCal = data;
              console.log('listCal data: ', listCal);  

             let startDate: Date,
             endDate: Date,
             event: CalendarEvent;
             let colors: Array<Color> = [new Color(200, 188, 26, 214), new Color(220, 255, 109, 130), new Color(255, 55, 45, 255), new Color(199, 17, 227, 10), new Color(255, 255, 54, 3)];
             let events: Array<CalendarEvent> = new Array<CalendarEvent>();
             for (let i = 1; i < listCal.length; i++) {
                  event = new CalendarEvent(listCal[i].title, new Date(listCal[i].date), new Date(listCal[i].date), false, colors[i * 10 % (listCal[i].colour.length - 1)]);    

                  events.push(event);     
              }
             //console.log(events);     
             return events;
           }
         );    

         //return events; HERE the events has no data because I am outside the .subscribe!
    }
Nabid
  • 197
  • 5
  • 24
  • 4
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Igor Feb 25 '19 at 19:35
  • `getCalendarEvents(): Array` should be `getCalendarEvents(): Observable>` (or `getCalendarEvents(): Promise>` if you want to use a Promise). – Igor Feb 25 '19 at 19:36
  • @Igor getCalendarEvents has a return type which is expecting events! But when I give events as the return it gives me nothing! But inside the subscribe the events has data! – Nabid Feb 25 '19 at 19:39
  • 1
    Read the answer from the suggested duplicate, it is well written and provides many examples including how to use Promises and Observables. – Igor Feb 25 '19 at 19:41
  • `getCalendarEvents has a return type which is expecting events!` <= you need to change your signature as I stated in my 2nd comment, you can't return the results directly in this methods because the source returns data asynchronously. – Igor Feb 25 '19 at 19:42
  • @Igor I have to return events in getCalendarEvents() because Calendar will be binded with the data of the events. So what should I do here? the for loop is used to bind the data to the list! – Nabid Feb 25 '19 at 19:48
  • @Igor Can I store the final iterated events and return it to the getCalendarEvents()? – Nabid Feb 25 '19 at 19:49
  • Add a field to your component: `calendarEvents: Array = [];` Change the end of the `subscribe` callback to `this.calendarEvents = events;` and remove `return events;`. Bind your html to `calendarEvents`. Alternatively change your method to return an asynchronous result and then use the [`async` pipe](https://angular.io/api/common/AsyncPipe) in your component's html. – Igor Feb 25 '19 at 19:52
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/189020/discussion-between-nabid-and-igor). – Nabid Feb 25 '19 at 20:15
  • This is giving me an error the way you suggested. May be I did sth wrong! Can you help? ` getCalendarEvents(): Array { calendarEvents: Array = []; var listCal:any = [] this.getCalendarData().subscribe((data: any) => { listCal = data; event: CalendarEvent; let events: Array = new Array(); FOR LOOP ENDS this.calendarEvents = events; } ); ` – Nabid Feb 25 '19 at 20:25

1 Answers1

3

You will need to treat this like an async function, because it is. Here are two ways:

import { Observable, Subject } from 'rxjs';
import { map } from 'rxjs/operators';

getCalendarEvents(): Observable<Array<CalendarEvent>> {
  return this.getCalendarData().pipe(map((data: any) => {
    // Your parsing code...
    return events;
  }));
}

// or:

getCalendarEvents(): Observable<Array<CalendarEvent>> {
  const result: Subject<Array<CalendarEvent>> = new Subject<Array<CalendarEvent>>();
  this.getCalendarData().subscribe((data: any) => {
    // Your parsing code...
    result.next(events);
    result.complete();
  });
  return result;
}
Ian MacDonald
  • 13,472
  • 2
  • 30
  • 51
  • 1
    do I need to import map from the lodash? map is giving me an error since it is not imported @Ian – Nabid Feb 25 '19 at 19:59
  • 1
    import { map } from 'rxjs/operators'; – Narendra Feb 26 '19 at 04:55
  • @Ian Are `result.next(events); and result.complete();` outside the for loop? – Nabid Feb 27 '19 at 17:41
  • Yes. They are in place of your `return` statement. – Ian MacDonald Feb 27 '19 at 19:35
  • @IanMacDonald do I need to use return result.asObservable() or just returning result will be fine? – Nabid Feb 28 '19 at 13:55
  • @IanMacDonald If I add `result.next(events); and result.complete();` just above the final return statement then the result.next(events) occurs an error because events is inside the subscribe! – Nabid Feb 28 '19 at 13:59
  • You do not _need_ to use `asObservable`, no. I'm not sure what you mean by the error, though. I have provided you an answer based on `getCalendarData`'s subscription response providing you with a single result (as though you had a `pipe(take(1))` in there, for instance). If that isn't the case, you'll need to treat the result differently. – Ian MacDonald Feb 28 '19 at 14:20