You need to sign in to do that
Don't have an account?
how to load FullcalendarJS in static resource for LWC? Fullcalendarjs css and jquery files are not loading got error.
Hi , I need to create custom calendar LWC Component . which fullcalendarjs version can i use for this component.
I tried with version 3 and 5,6 .
HTML:
<template>
<!-- Spinner to show on waiting screens -->
<template if:true={openSpinner}>
<lightning-spinner alternative-text="Loading" size="medium"></lightning-spinner>
</template>
<div class="slds-grid slds-wrap slds-theme_default">
<div class="slds-col slds-size_3-of-12">
<!-- To display list of events or any parent records
TODO: add drag items in this div to drop on fullcalendar.
-->
<div class=" slds-p-around_medium slds-border_right slds-scrollable_y" style="height:800px">
<div class="slds-clearfix">
<div class="slds-float_right">
<lightning-button icon-name="utility:add" slot="actions"
alternative-text="add" title="Add" size="small"
class="slds-p-around_medium"
label="Add Event"
onclick={addEvent}>
</lightning-button>
</div>
</div>
<template for:each={events} for:item="eachevent">
<lightning-card key={eachevent.id}
class="slds-p-left_medium slds-p-right_small">
<h3 slot="title">
<span class="slds-p-right_small">
<lightning-icon icon-name="standard:event" size="small">
</lightning-icon>
</span>
{eachevent.title}
</h3>
<lightning-button-icon icon-name="action:remove" slot="actions"
alternative-text="remove" title="Remove"
value={eachevent.id} size="small"
onclick={removeEvent}>
</lightning-button-icon>
<p class="slds-p-horizontal_small"> Start: <lightning-formatted-date-time value={eachevent.start} year="numeric" month="numeric" day="numeric" hour="2-digit"
minute="2-digit" time-zone="GMT" time-zone-name="short" hour12="true"></lightning-formatted-date-time></p>
<p class="slds-p-horizontal_small">End <lightning-formatted-date-time value={eachevent.end} year="numeric" month="numeric" day="numeric" hour="2-digit"
minute="2-digit" time-zone="GMT" time-zone-name="short" hour12="true"></lightning-formatted-date-time></p>
</lightning-card>
</template>
</div>
</div>
<div class="slds-col slds-size_9-of-12">
<!-- fullcalendar sits in this div -->
<div id="calendar" class="fullcalendarjs"></div>
</div>
</div>
JS:
import { LightningElement, track, wire } from 'lwc';
import { loadScript,loadStyle } from 'lightning/platformResourceLoader';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import FullCalendarJS from '@salesforce/resourceUrl/FullCalendarJS';
import fetchEvents from '@salesforce/apex/FullCalendarController.fetchEvents';
import createEvent from '@salesforce/apex/FullCalendarController.createEvent';
import deleteEvent from '@salesforce/apex/FullCalendarController.deleteEvent';
import { refreshApex } from '@salesforce/apex';
/**
* @description: FullcalendarJs class with all the dependencies
*/
export default class FullCalendarJs extends LightningElement {
//static renderMode ='light';
//To avoid the recursion from renderedcallback
fullCalendarJsInitialised = false;
//Fields to store the event data -- add all other fields you want to add
title;
startDate;
endDate;
eventsRendered = false;//To render initial events only once
openSpinner = false; //To open the spinner in waiting screens
openModal = false; //To open form
@track
events = []; //all calendar events are stored in this field
//To store the orignal wire object to use in refreshApex method
eventOriginalData = [];
//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
console.log(data);
let events = data.map(event => {
return { id : event.Id,
title : event.Subject,
start : event.StartDateTime,
end : event.EndDateTime,
allDay : event.IsAllDayEvent};
});
this.events = JSON.parse(JSON.stringify(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';
}
}
/**
* Load the fullcalendar.io in this lifecycle hook method
*/
renderedCallback() {
// loadScript(this, jQuery ),
// Performs this operation only on first render
if (this.fullCalendarJsInitialised) {
return;
}
this.fullCalendarJsInitialised = true;
console.log('InsidefullCalendarJsInitialised');
console.log(FullCalendarJS);
console.log(jQuery);
// Executes all loadScript and loadStyle promises
// and only resolves them once all promises are done
Promise.all([
loadScript(this, FullCalendarJS + "/fullcalendarjquerymoment/jquery.min.js"),
loadScript(this, FullCalendarJS + "/fullcalendarjquerymoment/moment.min.js"),
loadScript(this, FullCalendarJS + "/fullcalendarminjs/fullcalendar.min.js"),
loadStyle(this, FullCalendarJS + "/fullcalendarprintmincss/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');
console.log($ele);
let 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
//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
});
}
//TODO: add the logic to support multiple input texts
handleKeyup(event) {
this.title = event.target.value;
}
//To close the modal form
handleCancel(event) {
let ev = event.target.value;
if(ev){
this.openModal = false;
}
}
//To save the event
handleSave(event) {
let ev = event.target.value;
if(ev){
//let events = this.events;
this.openSpinner = true;
//get all the field values - as of now they all are mandatory to create a standard event
//TODO- you need to add your logic here.
this.template.querySelectorAll('lightning-input').forEach(ele => {
if(ele.name === 'title'){
this.title = ele.value;
}
if(ele.name === 'start'){
this.startDate = ele.value.includes('.000Z') ? ele.value : ele.value + '.000Z';
}
if(ele.name === 'end'){
this.endDate = ele.value.includes('.000Z') ? ele.value : ele.value + '.000Z';
}
});
//format as per fullcalendar event object to create and render
let newevent = {title : this.title, start : this.startDate, end: this.endDate};
console.log(this.events);
//Close the modal
this.openModal = false;
//Server call to create the event
createEvent({'event' : JSON.stringify(newevent)})
.then( result => {
const $ele = this.template.querySelector("div.fullcalendarjs");
//To populate the event on fullcalendar object
//Id should be unique and useful to remove the event from UI - calendar
newevent.id = result;
//renderEvent is a fullcalendar method to add the event to calendar on UI
//Documentation: https://fullcalendar.io/docs/v3/renderEvent
//$.noConflict();
//jQuery( document ).ready(function( $ ){
$ele.fullCalendar( 'renderEvent', newevent, true );//});
//To display on UI with id from server
this.events.push(newevent);
//To close spinner and modal
this.openSpinner = false;
//show toast message
this.showNotification('Success!!', 'Your event has been logged', 'success');
})
.catch( error => {
console.log(error);
this.openSpinner = false;
//show toast message - TODO
this.showNotification('Oops', 'Something went wrong, please review console', 'error');
})
}
}
/**
* @description: remove the event with id
* @documentation: https://fullcalendar.io/docs/v3/removeEvents
*/
removeEvent(event) {
//open the spinner
this.openSpinner = true;
//delete the event from server and then remove from UI
let eventid = event.target.value;
deleteEvent({'eventid' : eventid})
.then( result => {
console.log(result);
const $ele = this.template.querySelector("div.fullcalendarjs");
console.log(eventid);
$ele.fullCalendar( 'removeEvents', [eventid] );
this.openSpinner = false;
//refresh the grid
return refreshApex(this.eventOriginalData);
})
.catch( error => {
console.log(error);
this.openSpinner = false;
});
}
/**
* @description open the modal by nullifying the inputs
*/
addEvent(event) {
let ev = event.target.value;
if(ev){
this.startDate = null;
this.endDate = null;
this.title = null;
this.openModal = true;
}
}
/**
* @description method to show toast events
*/
showNotification(title, message, variant) {
console.log('enter');
const evt = new ShowToastEvent({
title: title,
message: message,
variant: variant,
});
this.dispatchEvent(evt);
}
}
Apex class:
public with sharing class FullCalendarController {
public class EventException extends Exception {}
/**
* @description: To retrieve the most recent events
*/
@AuraEnabled(cacheable=true)
public static List<Event> fetchEvents() {
return [SELECT Id, Subject, StartDateTime, IsAllDayEvent, EndDateTime
FROM Event
ORDER BY CreatedDate DESC
LIMIT 100];
}
/**
* @description To create an event from web component
* @param event - json string with event details - title, start and end for now
*/
@AuraEnabled
public static Id createEvent(String event){
//The following logic to be replaced with your respective event object
if(String.isBlank(event)){
return null;
}
Map<String, Object> eventMap = (Map<String, Object>) JSON.deserializeUntyped(event);
Event newEvent = new Event();
newEvent.Subject = eventMap.get('title') != null ? (String)eventMap.get('title') : null;
String startdate = eventMap.get('start') != null ?
((String)eventMap.get('start')).replace('T', ' ').replace('.000Z', '') :
null;
String endDate = eventMap.get('end') != null ?
((String)eventMap.get('end')).replace('T', ' ').replace('.000Z', '') :
null;
newEvent.StartDateTime = startdate != null ? Datetime.valueOfGmt(startdate) : null;
newEvent.EndDateTime = endDate != null ? Datetime.valueOfGmt(endDate) : null;
// newEvent.IsAllDayEvent = eventMap.get('start') != null ? eventMap.get('start') : null;
insert newEvent;
return newEvent.Id;
}
/**
* @description To delete an event from web component
* @param eventid - event id to delete from the component
*/
@AuraEnabled
public static void deleteEvent(Id eventid) {
if(eventid != null){
delete [SELECT Id FROM Event Where Id=:eventid];
}else{
throw new EventException('Event id is not passed');
}
}
}
The FullCalendarJS library is quite versatile and supports different versions. However, based on your provided code, it seems that you are using the FullCalendar v3 library.
In your JavaScript code, you're using methods like fullCalendar, renderEvents, renderEvent, and removeEvents, which are specific to FullCalendar v3. These methods have been changed in newer versions, such as FullCalendar v4 and v5.
If you want to use a different version of FullCalendarJS, you'll need to make some modifications to your code based on the version you choose. Here are the steps you can follow:
Identify the version of FullCalendarJS you want to use. You can visit the FullCalendarJS website (https://fullcalendar.io/) and check the documentation for the version you prefer.
Based on the chosen version, update your import statement in the JavaScript code to load the correct FullCalendarJS resource. For example, if you want to use FullCalendar v5, you would replace the import statement: with the appropriate import statement for FullCalendar v5.
Update your renderedCallback() method to initialize the correct version of FullCalendarJS. The initialization code, options, and method names may differ based on the version you choose. Refer to the FullCalendarJS documentation for your chosen version to understand the initialization process and make the necessary adjustments.
By following these steps and referring to the FullCalendarJS documentation for your chosen version, you should be able to integrate the desired version of FullCalendar into your custom LWC component successfully.
Hope this helps !
Thank you.