1

I am trying to use FullCalendar 4.4.0 Timeline View inside a LWC component.

html

<template>
    <section class="slds-card slds-p-around_medium">
        <div class="calendar" lwc:dom="manual"></div>
    </section>
</template>

js

import { LightningElement } from "lwc";
import { loadStyle, loadScript } from "lightning/platformResourceLoader";
import fc_core from "@salesforce/resourceUrl/fullcalendar_core";
import fc_timeline from "@salesforce/resourceUrl/fullcalendar_timeline";
import fc_resource_common from "@salesforce/resourceUrl/fullcalendar_resource_common";
import fc_resource_timeline from "@salesforce/resourceUrl/fullcalendar_resource_timeline";

export default class ResourceTimeline extends LightningElement {
    connectedCallback() {

        loadStyle(this, fc_core + "/main.css")
            .then(() => {
                loadStyle(this, fc_timeline + "/main.css")
                    .then(() => {
                        loadStyle(this, fc_resource_timeline + "/main.css")
                            .then(() => {
                                loadScript(this, fc_core + "/main.js")
                                    .then(() => {
                                        loadScript(this, fc_timeline + "/main.js")
                                            .then(() => {
                                                loadScript(this, fc_resource_common + "/main.js")
                                                    .then(() => {
                                                        loadScript(this, fc_resource_timeline + "/main.js")
                                                            .then(() => {
                                                                this.createCalendar();
                                                            })
                                                            .catch(err => this.handleError(err));
                                                    })
                                                    .catch(err => this.handleError(err));
                                            })
                                            .catch(err => this.handleError(err));
                                    })
                                    .catch(err => this.handleError(err));
                            })
                            .catch(err => this.handleError(err));
                    })
                    .catch(err => this.handleError(err));
            })
            .catch(err => this.handleError(err));
    }

    handleError(err) {
        // eslint-disable-next-line no-console
        console.error(err);
    }

    createCalendar() {
        const calendarEl = this.template.querySelector("div");
        // eslint-disable-next-line no-undef
        const calendar = new FullCalendar.Calendar(calendarEl, {
            plugins: ["interaction", "resourceTimeline"],
            timeZone: "UTC",
            defaultView: "resourceTimelineDay",
            aspectRatio: 1.5,
            header: {
                left: "prev,next",
                center: "title",
                right: "resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth"
            },
            editable: true,
            resourceLabelText: "Rooms",
            resources: [
                { id: "a", title: "Auditorium A" },
                { id: "b", title: "Auditorium B", eventColor: "green" },
                { id: "c", title: "Auditorium C", eventColor: "orange" },
                {
                    id: "d",
                    title: "Auditorium D",
                    children: [
                        { id: "d1", title: "Room D1" },
                        { id: "d2", title: "Room D2" }
                    ]
                },
                { id: "e", title: "Auditorium E" },
                { id: "f", title: "Auditorium F", eventColor: "red" },
                { id: "g", title: "Auditorium G" },
                { id: "h", title: "Auditorium H" },
                { id: "i", title: "Auditorium I" },
                { id: "j", title: "Auditorium J" },
                { id: "k", title: "Auditorium K" },
                { id: "l", title: "Auditorium L" },
                { id: "m", title: "Auditorium M" },
                { id: "n", title: "Auditorium N" },
                { id: "o", title: "Auditorium O" },
                { id: "p", title: "Auditorium P" },
                { id: "q", title: "Auditorium Q" },
                { id: "r", title: "Auditorium R" },
                { id: "s", title: "Auditorium S" },
                { id: "t", title: "Auditorium T" },
                { id: "u", title: "Auditorium U" },
                { id: "v", title: "Auditorium V" },
                { id: "w", title: "Auditorium W" },
                { id: "x", title: "Auditorium X" },
                { id: "y", title: "Auditorium Y" },
                { id: "z", title: "Auditorium Z" }
            ],
            events: null
        });

        calendar.render();
    }
}

I've imported parts of the FullCalendar libraries:

  1. fullcalendar-4.4.0.zip
  2. fullcalendar-scheduler-4.4.0.zip

As static resources:

  1. fullcalendar_core
  2. fullcalendar_resource_common
  3. fullcalendar_resource_timeline
  4. fullcalendar_timeline

As per the example code

But when I open the page with the LWC on it, I get this error message:

Resource_Timeline:1 Uncaught (in promise) undefined

The error message is not helpful.

After chaining the promises, I am now getting these errors:

main.js:4561 Plugin file not loaded for interaction

and

resourceTimeline.js:66 TypeError: Illegal invocation

I've checked that each of the FullCalendar Javascript and CSS paths are correct using the developer console, and the code is being successfully downloaded to my browser.

Questions

  1. How do I get insight into the error happening inside the Promise.all that is causing the issue?
  2. Any ideas what the problem is?
  3. How can I fix it?
  4. Is the FullCalendar 4.4.0 not compatible with LockerService?
  • 1
    Have you tried <div class="calendar" lwc:dom="manual" ></div> ?... seems too short to make an answer. – Caspar Harmer Mar 18 '20 at 2:55
  • 1
    I wonder if code in one of the libraries self executes and is expecting the previous calendar code to be present - perhaps try a bunch of then() statements to ensure load order? – Caspar Harmer Mar 18 '20 at 3:18
  • @CasparHarmer - I've updated the code. I am getting a couple of errors main.js:4561 Plugin file not loaded for interaction and resourceTimeline.js:formatted:66 TypeError: Illegal invocation – Robs Mar 18 '20 at 3:29
  • That's a start... I guess you need to now debug what's going on inside main.js... man that new syntax only a mother could love... – Caspar Harmer Mar 18 '20 at 3:46
0

I think I may have a solution.

It looks like loading order is very important, and based on this library on github, I think you should be loading it like this:

renderedCallback() {
  if (this.fullCalendarInitialized) {
    return;
  }
  this.fullCalendarInitialized = true;

  Promise.all([
    loadScript(this, fc_core + "/main.js"),
    loadStyle(this, fc_core + "/main.css")
  ])
  .then(() => {
    //got to load core first, then plugins
    Promise.all([
   loadScript(this, fc_timeline + "/main.js"),
   loadStyle(this, fc_timeline + "/main.css"),
   loadScript(this, fc_resource_common + "/main.js"),
   loadStyle(this, fc_resource_common + "/main.css"),
   loadScript(this, fc_resource_timeline + "/main.js"),
   loadStyle(this, fc_resource_timeline + "/main.css")
    ]).then(() => {
      console.log("init");
      this.init();
    });
  })
  .catch(error => {
   //handle error stuff
});

I am not totally sure of all the elements to be loaded - you'll need to check them, as I can't see what resources you had in your original question.

  • I have a new answer for you - see above. – Caspar Harmer Mar 19 '20 at 17:06
  • Quick feedback on this answer: don't use blocking calls to load css (no need to put them in Promise.all() as they can load in the background in any order. Also use connectedCallback lifecycle hook. – POZ Jun 30 '20 at 9:26
  • Have you tried loading fullCalendar yourself? Perhaps you'd like to provide the canonical solution then? – Caspar Harmer Jun 30 '20 at 19:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.