Locker Service and Fullcalendar.io

Logan, I just happen to have a sample of Fullcalendar which displays events. But heads up .. it is not locker compatible. even though I have used ( Full Calendar: 3.1.0 & jQuery 2.2.4 ) as recommended in the non-exhaustive list of libs.

When locker service is enabled: You would get the following the error

Locker Activated Error FullCalendar

This is quite an ongoing issue,

FullCalendar lib with LockerService

which salesforce is aiming to fix it before the mandatory locker service critical update as per the comments from the sfdc team.

However, for now, you could disable the locker service, and get the components to work as expected.

Locker Deactivated

You would be able to see the calendar as follows

FullCalendar

The logic for the fullcalendar as follows:

Component / App :

<aura:application access="global" controller="FullCalendarController" extends="force:slds">
    <link href="{!$Resource.FullCalendar+'/fullcalendar.print.min.css'}" rel="stylesheet" media="print" />
    <ltng:require styles="{!join(',', $Resource.FullCalendar + '/fullcalendar.min.css')}" 
                  scripts="{!join(',', $Resource.FullCalendar + '/jquery-2.2.4.min.js', $Resource.FullCalendar + '/fullcalendar.min.js' , $Resource.FullCalendar + '/moment.min.js', $Resource.FullCalendar + '/moment-timezone.min.js', $Resource.FullCalendar + '/moment-timezone-with-data-2012-2022.min.js', $Resource.FullCalendar + '/jquery-ui.min.js')}" 
                  afterScriptsLoaded="{!c.scriptsLoaded}" />
    <aura:attribute name="events" type="Object[]" />

    <div class="slds-grid calendarContainer">
        <div class="slds-col">
            <div aura:id="calendar"></div>
        </div>
    </div>

</aura:application>

Controller.js :

({
    scriptsLoaded: function(cmp,evt,helper){
        var events = cmp.get("v.events");
        if(!events.length)
        {
            helper.fetchEvents(cmp);
        }
    }
})

Helper.js :

({
    loadDataToCalendar :function(component,data){
        var today = moment().format('YYYY-MM-DD');
        var ele = component.find('calendar').getElement();
        /* Header section left intentionally blank to remove the header buttons */
        $(ele).fullCalendar({
            aspectRatio: 2.50,
            header: {
                left: '',
                center: '',
                right: '',
            },
            defaultDate: today,
            navLinks: true,
            navLinkDayClick: $A.getCallback(function(date, jsEvent) {

            }),
            editable: true,
            eventLimit: true,
            events:data,
            eventClick: $A.getCallback(function(calEvent, jsEvent, view) {
                var editRecordEvent = $A.get("e.force:editRecord");
                editRecordEvent.setParams({
                    "recordId": calEvent.id
                });
                editRecordEvent.fire();
            })
        });
    },
    tranformToFullCalendarFormat : function(component,events) {
        var eventArr = [];
        for(var i = 0;i < events.length;i++){
            eventArr.push({
                'id':events[i].Id,
                'start': moment.tz(events[i].StartDateTime, "America/Los_Angeles"),
                'end': moment.tz(events[i].EndDateTime, "America/Los_Angeles"),
                'title':events[i].Subject
            });
        }
        return eventArr;
    },
    fetchEvents : function(component) {
        var action = component.get("c.getEvents"); 
        var self = this;
        action.setCallback(this, function(response) {
            var state = response.getState();
            console.log(state);
            if(component.isValid() && state === "SUCCESS"){
                var eventArr = self.tranformToFullCalendarFormat(component,response.getReturnValue());
                self.loadDataToCalendar(component,eventArr);
                component.set("v.events",eventArr);
            }
        });

        $A.enqueueAction(action); 
    }
})

Apex Controller :

public class FullCalendarController {
    @AuraEnabled
    public static List<Event> getEvents(){
        return [SELECT AccountId,EndDateTime,Id,StartDateTime,Subject FROM Event];
    }
}

Note: The markup provided above does not contain the entire logic for the all components shown in the fullCalendar view. For instance the logic to change the week or month etc or fire a new event creation etc,

Hope this helps.


Are people altering the libraries to make them compliant, or is Salesforce working to make sure that their requirements don't have such an impact on heavily utilized open source libraries such as Fullcalendar?

Modern libraries tend to be CSP-compliant, so the general answer is neither. However, it is understood that Salesforce has tweaked the security as much as possible to remain safe and yet allow libraries like this to work. It's understood that these allowances are minimal.

It would be difficult for a typical developer to modify one of these libraries to be compliant with Locker Service. It wouldn't surprise me at all if at least a few open source projects have had issues or pull requests logged directly against their github repo to fix minor security issues, but this isn't publicly documented by salesforce, as near as I can tell.

Are there libraries out there that people have already created that are Locker compliant that can be downloaded?

Generally, developers following best practices will find they are already LockerService compliant. @KeithC posted a link that includes "known-good" versions of a few popular libraries. It appears that salesforce.com regularly tests these libraries to make sure that LockerService doesn't break them.

Are there any links people can share that show recent examples of implementing Fullcalendar in a Locker Service enabled environment?

I don't know of any such examples, but I would invite anyone who reads this answer to edit in a link or add a comment.