0

We are using FullCalendar.io version 3 for Salesforce LWC component. Time by time, we are facing the rendering issues and instead of calendar rendering we see the error message

LWC component's @wire target property or method threw an error during value provisioning. Original error: [$(...).fullCalendar is not a function]]

(Please see screen shot attached). This error appears sometimes, but after screen refresh it works perfectly fine. But it still confuses users and they complain.

Here is Our code below. Please advice what is wrong and what can be enhanced that we do not face this error message without migrating to V4 or higher?

renderedCallback() {
    // Performs this operation only on first render
    if (this.fullCalendarJsInitialised) {
        return;
    }
    this.fullCalendarJsInitialised = true;
 
    // Executes all loadScript and loadStyle promises
    // and only resolves them once all promises are done
    Promise.all([
        loadScript(this, FullCalendarJS + "/FullCalendarJS/jquery.min.js"),
        loadScript(this, FullCalendarJS + "/FullCalendarJS/moment.min.js"),
        loadScript(this, FullCalendarJS + "/FullCalendarJS/fullcalendar.min.js"),
        loadStyle(this, FullCalendarJS + "/FullCalendarJS/fullcalendar.min.css"),
    ])
    .then(() => {
        //initialize the full calendar
        this.initialiseFullCalendarJs();
    })
    .catch((error) => {
        console.error({
            message: "Error occured on FullCalendarJS",
            error,
        });
    });

    initialiseFullCalendarJs() {
        const ele = this.template.querySelector("div.fullcalendarjs");
        const modal = this.template.querySelector('div.modalclass');
        var self = this;
        //To open the form with predefined fields
        //TODO: to be moved outside this function
        function openActivityForm(startDate, endDate){
            self.startDate = startDate;
            self.endDate = endDate;
            self.openModal = true;
        }
        //Actual fullcalendar renders here - https://fullcalendar.io/docs/v3/view-specific-options
        $(ele).fullCalendar({
            header: {
                left: "prev,next today",
                center: "title",
                right: "month,agendaWeek,agendaDay",
            },
            
            defaultDate: new Date(), // default day is today - to show the current date
            defaultView : 'agendaWeek', //To display the default view - as of now it is set to week view
            navLinks: true, // can click day/week names to navigate views
            //editable: true, // To move the events on calendar - TODO 
            selectable: true, //To select the period of time
            timeZone: 'local',
            nextDayThreshold: '00:00:00',
             
            //To select the time period : https://fullcalendar.io/docs/v3/select-method
            select: function (startDate, endDate) {
                let stDate = startDate.format();
                let edDate = endDate.format();     
                openActivityForm(stDate, edDate);
            },
            eventLimit: true, // allow "more" link when too many events
            //events: this.events, // all the events that are to be rendered - can be a duplicate statement here
        });
    }

    //Get data from server - in this example, it fetches from the event object
    @wire(fetchEvents)
    eventObj(value){
        this.eventOriginalData = value; //To use in refresh cache
        const {data, error} = value;
        if(data){
            //format as fullcalendar event object
            let events = data.map(event => {
                var sttime = new Date(event.StartDateTime);
                var etime = new Date(event.EndDateTime);
                return { id : event.Id, 
                         title : event.Subject, 
                         start : sttime,
                         end : etime};
            });
            this.events = events;
            console.log(this.events);
            this.error = undefined;
 
            //load only on first wire call - 
            // if events are not rendered, try to remove this 'if' condition and add directly 
            if(! this.eventsRendered){
                //Add events to calendar
                const ele = this.template.querySelector("div.fullcalendarjs");
                $(ele).fullCalendar('renderEvents', this.events, true);
                this.eventsRendered = true;
            }
        } else if(error){
            this.events = [];
            this.error = 'No events are found';
        }
   }

////////////////////APEX CONTROLLER////////////////////////////

@AuraEnabled(cacheable=true)
public static List<Recommendation> FetchRecos() {
    String User521Id = [Select Id, X521_ID__c From User Where Id = :UserInfo.getUserId()][0].X521_ID__c;
    return [SELECT Id, Cathegory__c, isActioned__c, Description, ZipCode__c, PostInputAccepted__c, PostInputRejected__c, AccountName__c , Priority__c  
            from Recommendation 
            where Owner521Id__c =:User521Id
            AND isActioned__c = false
            ORDER BY Priority__c ASC
            LIMIT 50];
}
1
  • Is LWS enabled on the org? What does your LWC template look like? Please edit the question to add these details.
    – Phil W
    Dec 12, 2022 at 12:48

1 Answer 1

0

Your problem is this bit:

if(! this.eventsRendered){
    //Add events to calendar
    const ele = this.template.querySelector("div.fullcalendarjs");
    $(ele).fullCalendar('renderEvents', this.events, true);
    this.eventsRendered = true;
}

If $ loads before fetchEvents returns data, no error will appear. Otherwise, if the wire gets done first, then $ is not defined and you'll get this error. This is known as a "race condition."

You'll want a separate method to wait for this.events to be set and $ to be available, then call that method from both places.

calendarLoaded = false;
renderCalendar() {
  if(!this.calendarLoaded || !this.events) {
    return;
  }
  this.initialiseFullCalendarJs();
}

...

// Promise.all is here from renderedCallback
.then(() => {
    //initialize the full calendar
    this.calendarLoaded = true;
    this.renderCalendar();
})

...

// In @wire(fetchEvents) ...
if(!this.eventsRendered) {
  this.renderCalendar();
}

In this manner, you should get the correct behavior no matter which way the libraries and data load.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .