Search code examples
javascriptangulartypescriptfullcalendarfullcalendar-6

Angular Full Calendar / Chronofy - resize an event that uses constraints intended for limiting drag and drop function


I am currently trying to build an availability calendar so we can book meetings within the available times.

If the times are unavailable we should not be able to drop and event on that area.

I have this concept working. However I cannot resize the event if I wanted to extend or shorten the event duration.

It only works if I remove the constraint property. But then this allows me to drag and drop on unavailable slots.

I make 2 API calls, one to get the availability data from Chronofy and one to get the events that have been scheduled for that period.

I combine the arrays and set them on the events property of the Full Calendar Options config to populate the Full Calendar with the events.

This is just proof of concept code so it will be very rough.

    this.setEventSources([
    ...available_periods.available_periods.map((ap: any) => {
      ap.groupId = 1;
      ap.display = 'inverse-background';
      return ap;
    }), 
    ...res.events.events.map((e: any) => {
      e.id = e.event_id,
      e.display ='auto';
      e.className = 'tester';
      e.editable = true;
      e.durationEditable = true;
      e.startEditable = true;
      e.constraint = 1;
      return e;
    })]);

this method takes an array and just sets the event property on the Full Calendar options.

Notice the first array that I spread. This is the available periods data, I use the inverse-background display option as I want to show the slots to be blank for availability and the unavailable slots to be greyed out. This achieves that.

I also set a groupId on this as it is required to group the events together as per the documentation.

On the second array that contains the booked events , I set a constraint so that it will not allow me to overlap when dragged an event that has a groupId of 1.

This also works as intended.

However my issue is that with this constraint it does not allow me to resize / extend the duration of that event.

Could any one please help or point me in the correct direction on how to achieve this?

Thank you


Solution

  • I can think of a couple of different ways to work round this:

    Option 1

    If an event is booked into a period, then you should still include the time period covered in your "available periods" data. It won't show as available to the user because an event will be over the top of it, but it will mean that you can drag and resize the event within that time period, as long as it doesn't extend into an unavailable section.

    Sample data:

      var events = [
        { "event_id": 1, "title": "Test 1", "start": "2024-01-05 09:00", "end": "2024-01-05 11:00"},
        { "event_id": 1, "title": "Test 2", "start": "2024-01-06 11:00", "end": "2024-01-06 12:30"},
        { "event_id": 1, "title": "Test 3", "start": "2024-01-02 10:00", "end": "2024-01-03 11:00"},
        { "event_id": 1, "title": "Test 4", "start": "2024-01-04 10:00", "end": "2024-01-04 11:10"},
      ];
      var available_periods = [
        { "start": "2024-01-01 09:00", "end": "2024-01-01 12:00" },
        { "start": "2024-01-02 10:00", "end": "2024-01-03 11:00"},
        { "start": "2024-01-04 09:00", "end": "2024-01-04 12:00" },
        { "start": "2024-01-05 09:00", "end": "2024-01-05 13:00"},
        { "start": "2024-01-06 11:00", "end": "2024-01-06 12:30"},
        { "start": "2024-01-06 13:00", "end": "2024-01-06 17:00" },
      ];
    

    Live demo: https://codepen.io/ADyson82/pen/dyrVOdV

    Option 2

    Rather than using inverse-background events to show availability, you could use regular background events and situate these in the unavailable times, and configure that calendar so that users cannot drag or resize over these background events. Any slot which doesn't contain a background event, or booked event, is then considered as available.

    N.B. If you have regular period of unavailability which occur in a predictable, repeating pattern you can consider representing those more efficiently with the businessHours setting and then setting businessHours as the event constraint value.

    Sample data:

      var events = [
        { "event_id": 1, "title": "Test 1", "start": "2024-01-05 09:00", "end": "2024-01-05 11:00"},
        { "event_id": 1, "title": "Test 2", "start": "2024-01-06 11:00", "end": "2024-01-06 12:30"},
        { "event_id": 1, "title": "Test 3", "start": "2024-01-02 10:00", "end": "2024-01-03 11:00"},
        { "event_id": 1, "title": "Test 4", "start": "2024-01-04 10:00", "end": "2024-01-04 11:10"},
      ];
      var unavailable_periods = [
        { "start": "2023-12-31 00:00", "end": "2024-01-01 00:00" },
        { "start": "2024-01-01 12:00", "end": "2024-01-02 00:00"},
        { "start": "2024-01-02 09:00", "end": "2024-01-03 10:00"},
        { "start": "2024-01-03 11:00", "end": "2024-01-04 00:00" },
        { "start": "2024-01-04 12:00", "end": "2024-01-05 00:00" },
        { "start": "2024-01-05 13:00", "end": "2024-01-06 00:00"},
        { "start": "2024-01-06 09:00", "end": "2024-01-06 11:00"},
        { "start": "2024-01-06 12:30", "end": "2024-01-06 13:00" },
        { "start": "2024-01-06 17:00", "end": "2024-01-07 00:00" }
      ];
    

    Code changes:

    unavailable_periods.map
    
        ap.display = 'background';
    

    (note change of variable name, and change of "inverse-background" to "background")

    and

      events.map((e) => {
        e.id = e.event_id,
        e.display ='auto';
        e.className = 'tester';
        e.editable = true;
        e.durationEditable = true;
        e.startEditable = true;
        return e;
      })
    

    (note removal of eventConstraint property)

    and an extra option:

    eventOverlap: function (stillEvent, movingEvent) {
      return stillEvent.display != "background";
    },
    

    Live demo: https://codepen.io/ADyson82/pen/dyrZOXp

    Note that the above code and samples are written in regular JavaScript as I'm not familiar with Angular. However the principles are the same and it will only require minor syntax changes I expect in order to work with Angular.