Search code examples
javascriptfullcalendarmomentjsfullcalendar-4

Allow events to be dragged only onto background events


I am managing appointments on fullcalendar. I have available slots of time where I can create new appointments. Also I can drag appointments onto available time slots which are shown as background events.

I only want the drop functionality on background event slots.

I have tried the eventOverlap method but it only works when the event is dropped on a background event. If the event is dropped elsewhere then I am unable to detect whether I am dropping the event on background event or on empty slot.

var calendarEl = document.getElementById('calendar');

var calendar = new FullCalendar.Calendar(calendarEl, {
    defaultView: 'timeGridWeek',
    // height: 1080,
    plugins: ['dayGrid', 'timeGrid', 'interaction'],
    header: {
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay'
    },

    events: {
        url: getUrl(),
        failure: function() {
            toastr.error('Unable to load calendar data, Please try later');
        },
        success: function() {

        }
    },


    loading: function(bool) {

    },
    defaultDate: Date.now(),

    editable: true,
    eventLimit: true,
    eventClick: function(info) {

        if (info.event.extendedProps.type == 'Calendar') {
            showCreateModal(info.event);
        }
        if (info.event.extendedProps.type == "Appointment") {
            showUpdateModal(info.event);
        }
    },

    eventOverlap: function(stillEvent, movingEvent) {
        return stillEvent.extendedProps != '' && stillEvent.extendedProps.type === 'Calendar' ? true : false;
    },

    eventDrop: function(info) {
        // check if event is being dropped on past date / slot
        if (moment(info.event.start) < moment()) {
            info.revert();
            return;
        }

        // check if event is being dropped on future slot
        if (moment(info.event.start) > moment()) {
            swal({
                    title: "Are you sure?",
                    text: "You are about to re-schedule this appointment!",
                    icon: "warning",
                    // buttons: true,
                    buttons: ["No", "Yes !"],
                    dangerMode: true,
                })
                .then((response) => {
                    if (response) {
                        submitForm(false, true, info.event);
                    } else {
                        info.revert();
                    }
                });
        }

    }

});

calendar.render();

This is what I want:

enter image description here


Solution

  • You're correct that eventOverlap doesn't help you here, because it's only triggered when the event is dropped onto a background event. It doesn't help you when the event is dropped somewhere else.

    In fullCalendar 4 you can achieve what you need via the eventConstraint setting. This allows you to limit event dragging to specific windows of time. As the documentation says, you can provide a groupId value to this setting, and then

    ...events that are being dragged or resized must be fully contained by at least one of the events linked to by the given groupId.

    All you need to do as well as that is give all your background events the same groupId.

    For example, if you set:

    eventConstraint: 1
    

    and then have entries such as these within your event data:

      {
        start: "2019-07-10 09:00",
        end: "2019-07-10 12:00",
        rendering: "background",
        groupId: 1
      },
      {
        start: "2019-07-11 09:00",
        end: "2019-07-11 12:00",
        rendering: "background",
        groupId: 1
      },
    

    This would mean that you would only be allowed to drag or resize an existing calendar event if you drag/resize it so that it falls entirely within the time periods covered by those background events which have a groupId of 1.

    Here's a working demonstration: https://codepen.io/ADyson82/pen/jjdEjB