Search code examples
angularscheduleprimengangular2-observables

angular2 Implementing FullCalendar-Scheduler with PrimeNG-Scheduler


FullCalendar has an add-on called Scheduler which I am trying to use with PrimeNG-Schedule component. Looking at the PrimeNG docs, there is an 'options' property that I can use to send arbitrary information to FullCalendar. This does work but when I hook up to data retrieval to an async API, it causes issues.

API uses Observables which I then subscribe to in the component. This works fine for Events as the view gets updated automatically when events are changed.

However, when supplying the FullCalendar with 'resources' via the PrimeNG 'options' property, things don't work as expected because the code to set the 'options' property is run before the API call has a chance to come back and is thus empty.

I am sure of this because if I hard-code the resources, things work.

I can think of a few ways to remedy the issue:

  1. Make the calls synchronous (would like to avoid this)

  2. Wait for all data to load and then (re)render the view (makes this almost the same as #1)

  3. Configure the options.resources property such that when it changes, the view gets updated, just like it does for events (this is the best option but not sure if it's even possible)

I would appreciate any help. Thank you.

<p-schedule 
    [events]="events" 
    [businessHours]="businessHours"
    [options]="optionConfig"
    >
</p-schedule>

My (for now) dummy API

getEvents() {
    return this.http
    .get('assets/api/mockEvents.json')
    .map((response : Response) => <Appointment[]>response.json().data)
    .catch(this.handleError);
  }

  getResources() {
    return this.http
    .get('assets/api/mockResources.json')
    .map((response : Response) => <Resource[]>response.json().data)
    .catch(this.handleError);
  }

Component file

ngOnInit() {

  this.schedulerService.getEvents()
      .subscribe(events=> this.events = events);

      this.schedulerService.getResources()
      .subscribe(resources => this.resources = resources);
      // ***** If the following code is uncommented, resources are displayed in Schedule view ****
    // this.resources = [
    //     new Resource(1, "Dr. Hibbert", "blue", true, new BusinessHours("08:00", "16:00")),
    //     new Resource(2, "Dr. Simpson", "green", true, new BusinessHours("10:00", "18:00"))
    // ];
    this.optionConfig = {
      "resources": this.resources
      }
}

Edit: One thing I thought of is, setting the this.resources property only via it's setter method. This way, I know exactly when the value is being set, but the problem still remains how can I push the new value to schedule component after it has been initialized.


Solution

  • I Got it!

    Using *ngIf to delay rendering of the component until this.resources has data. I added a new boolean property isDataAvailable defaulting it to false. Then, this.schedulerService.getResources() sets it to true only after resources API call returns, at which point I also set the resources property in optionConfig

    ngOnInit() {
        this.loadResources();
    }
    
    private loadResources() {
        this.schedulerService.getResources()
          .subscribe(
              resources => {
                this.resources = resources;
                this.optionConfig['resources'] = this.resources;
    
                this.isDataAvailable = true;
              } ,
              error => console.log(error)
              );  
      }
    

    Template:

    <div *ngIf="isDataAvailable; else elseBlock">
         <p-schedule
             [events]="appointments" 
             [options]="optionConfig"
             (onDayClick)="handleDayClick($event)"
             (onEventClick)="handleEventClick($event)"
             (onViewRender)="loadAppointments($event)">
         </p-schedule>
    </div>
    <ng-template #elseBlock>Loading....</ng-template>