Reordering a Day’s Events in FullCalendar

To help us schedule things in our new CMS, we’ve been using Adam Shaw’s FullCalendar jQuery plugin fairly extensively.

It does a good job of providing a pretty robust and easy to use Calendar, including some nice drag and drop functionality. One thing it doesn’t support is the ability to easily reorder events inside of a specific date, by simply dragging them around. Now, you can assign each event a time, and then they will order by that time, but that requires you to edit each one individually, which is kind of a pain. It doesn’t actually matter to us the time of the event that we’re scheduling, just the date, and we need a way to order them in some way.

I was originally hoping to be able to just do a sortable call on the container that holds the events themselves, but that appears to be impossible due to the way FullCalendar works. If you look at the code it generates, the calendar is actually just a big table, with the events placed into their proper locations using absolute positioning. All the events for a day are not held in a unique container. They are not actually contained by the calendar itself. An example of an event:

<div class="fc-event fc-event-skin fc-event-hori fc-event-draggable fc-corner-left fc-corner-right"
 style="position: absolute; z-index: 8; left: 732px; width: 164px; top: 368px;">
 <div class="fc-event-inner fc-event-skin">
 <span class="fc-event-title">Event Title</span>
 </div>
 <div class="ui-resizable-handle ui-resizable-e"> </div>
</div>

To get around this limitation, we decided to go with a small colorbox popup that displayed itself when a date was clicked. FullCalendar supports this with relative ease. There is a dayClick event that is triggered when a day is clicked:

dayClick: function(date, allDay, jsEvent, view) {}

It only makes sense to reorder events if there are two or more, so the code actually does a quick jQuery getJSON call to verify the number of events, and then pops the colorbox:

jQuery.getJSON(url,  {
      dateString: dateStr
   },
   function(data){
      if (data.proceed) {
         jQuery.colorbox({href:"/featured_games/reorder/", data: {dateString: dateStr}, speed: 200, opacity: 0.25});
      } else {
         // not enough events to reorder
         // notify the user
      }
   }
);

The colorbox popup then uses a standard jQuery UI sortable call:

featured-games-popup

Clicking save sends a CSV list of the event IDs back to the server which then saves the events with slightly offset times. That allows the calendar to properly order them, and will allow the front end of the site to retrieve them in the order we want, simply by ordering the results by the event’s datetime.

var order = jQuery('#sortFeaturedGames').sortable('toArray').toString();

jQuery.getJSON(url, {
    order: order
  },
  function(data){
    if (data.proceed) {
      jQuery('#calendar').fullCalendar("refetchEvents");
      jQuery('#cboxClose').click();
      jQuery.jGrowl("Featured Games Reordered for <?php echo $date;?>.", 
      { header: 'Featured Games Reordered', position: 'bottom-left' });
    } else {
       jQuery.jGrowl("Unable to reorder Featured Games for <?php echo $date;?>.", 
      { header: 'An Error Occured', position: 'bottom-left' });
    }
  }
);

If it is successful, the JSON event data is refetched and the calendar is updated. Since the events now have slightly offset times, they will be ordered properly.

This entry was posted in jQuery / Javascript and tagged , , , . Bookmark the permalink.

2 Responses to Reordering a Day’s Events in FullCalendar

  1. AB says:

    Hey, this would be great to see in the fiddle. Some working example. We need to implement something similar.

    • Eric Brandel says:

      Hey, sorry. This is 5+ year old code that I haven’t touched in a long while and I actually don’t even have access to anymore, so I’m not 100% sure what it even looked like then. Also, I’m willing to bet FullCalendar is quite a bit different now anyways, as is jQuery UI.

Leave a Reply to AB Cancel reply

Your email address will not be published. Required fields are marked *