5

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.

Rohan Fating
  • 2,135
  • 15
  • 24
Harinder
  • 333
  • 2
  • 3
  • 23
  • in your `ngOnInit` hook there is missing `this` in `.subscribe(resources => .resources = resources);` line, it should be `.subscribe(resources => this.resources = resources);` – Andriy Aug 25 '17 at 22:28
  • @Andriy Oops, made a mistake while writing the post. Just looked at my code and it does contain the `this` – Harinder Aug 26 '17 at 20:29
  • can you please reprocude the same problem on some plunker ? – Pardeep Jain Aug 27 '17 at 11:22

2 Answers2

0

PS: I am not able to Reproduce your problem so suggesting you without tested

you can use asynch pipe of angular2 to gets load view once you data came like this in view part

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

or even you can assign directly resource using asynch pipe instead of wrapping into optionConfig if suitable.

by doing so you neither need to make synchronous call nor need to re redner view once data loaded.

if still problem is there let me know.

Pardeep Jain
  • 84,110
  • 37
  • 165
  • 215
0

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>
Harinder
  • 333
  • 2
  • 3
  • 23
  • yeah that is also a way but instead of this `async` pipe would be preferred as i mentioned in answer , also if you are using this use `[hidden]` instead of `*ngIf` – Pardeep Jain Aug 28 '17 at 04:58
  • Also have you tried the way i am suggested in my answer ? – Pardeep Jain Aug 30 '17 at 11:03
  • 1
    @PardeepJain I have not tried async yet, will give it a shot once I make up all the lost time on this issue. Thanks. – Harinder Sep 02 '17 at 21:47