FullCalendar 3.8.0在AngularJS中无法实现单日事件垂直拖拽排序
Got it, let's tackle this problem—you need to enable vertical drag-and-drop reordering for all-day events within the same day in FullCalendar 3.8.0's basicWeek view, right? The default FullCalendar drag functionality only lets you move events between dates, not reorder them on the same day. Here's how to make it work with your existing AngularJS + ngDraggable + ui-calendar setup:
核心思路
FullCalendar's eventOrder config lets you control event display order. We'll add a custom sortOrder field to each event, update this value when dragging, and tell FullCalendar to use this field for sorting. This way, dragging an event will adjust its position by modifying its sortOrder and re-rendering the calendar.
具体实现步骤
1. Add a custom sort field to events
First, add a sortOrder property to all your events (both initial dummy data and draggable objects) to track their display order:
// Dummy event data with sortOrder var eventEntities = [ { title : "Job Name One- #H", description : "Operation New Submittaly", start : $scope.droppableObjectsDate , end : $scope.droppableObjectsDate , allDay : true, sortOrder: 1 // Initial sort position } , { title : "Long Lead Time Name 2- #H", description : "Operation New Submittaly", start : $scope.droppableObjectsDate , end : $scope.droppableObjectsDate , allDay : true, sortOrder: 2 } ]; // Draggable objects with sortOrder $scope.draggableObjects = [ { title : "Job Name One- #H", description : "Operation New Submittal", start: $scope.droppableObjectsDate, end : $scope.droppableObjectsDate, allDay : true, sortOrder: 3 }, { title : "Long Lead Time Name 2- #H", description : "Operation New Submittal", start : $scope.droppableObjectsDate, end : $scope.droppableObjectsDate, allDay : true, sortOrder: 4 } ];
2. Configure FullCalendar to use the custom sort field
Update your uiConfig.calendar settings to sort events by the sortOrder field:
$scope.uiConfig = { calendar : { // ... keep your existing config eventOrder: "sortOrder", // Use our custom sort field // ... keep your existing config } }
3. Handle drag-and-drop for same-day events
Modify the eventDrop and onDropComplete1 methods to handle same-day reordering. We'll calculate the new sort position based on the drag target and update the event's sortOrder.
First, update the eventDrop handler for internal calendar events:
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view){ // Check if we're dragging within the same day (no day change, all-day event) if (dayDelta === 0 && allDay) { // Get all events on the same day var sameDayEvents = $scope.events.filter(e => moment(e.start).isSame(event.start, 'day') ); var targetElement = $(jsEvent.target).closest('.fc-event'); var siblingEvents = targetElement.siblings('.fc-event'); var targetSortOrder; // Determine drag direction (up/down) if (ui.position.top < targetElement.offset().top) { // Dragging up: set sortOrder to just above the previous event var prevEvent = siblingEvents.filter((i, el) => $(el).offset().top < ui.position.top).last(); targetSortOrder = prevEvent.length ? prevEvent.data('event').sortOrder - 0.5 : 0; } else { // Dragging down: set sortOrder to just below the next event var nextEvent = siblingEvents.filter((i, el) => $(el).offset().top > ui.position.top).first(); targetSortOrder = nextEvent.length ? nextEvent.data('event').sortOrder + 0.5 : sameDayEvents.length + 1; } // Update the event's sort order and re-render event.sortOrder = targetSortOrder; uiCalendarConfig.calendars.myCalendar.fullCalendar('rerenderEvents'); } }
Then, update onDropComplete1 for external events dragged into the calendar:
$scope.onDropComplete1 = function(data, evt) { var index = $scope.events.indexOf(data); if (index == -1) { // Get all events on the drop date var sameDayEvents = $scope.events.filter(e => moment(e.start).isSame(evt.start, 'day') ); // Set new event's sort order to the highest existing +1 data.sortOrder = sameDayEvents.length > 0 ? Math.max(...sameDayEvents.map(e => e.sortOrder)) + 1 : 1; data.start = evt.start; data.end = evt.start; $scope.events.push(data); // Re-render to apply the new order uiCalendarConfig.calendars.myCalendar.fullCalendar('rerenderEvents'); } }
4. Bind events to DOM elements for drag handling
Update the eventRender method to attach the event object to its DOM element (so we can access it during drag operations):
// Don't forget to inject $compile into your controller dependencies! eventRender: function(event, element, view){ element.data('event', event); // Bind event data to the DOM element // Add ng-drag attributes to enable internal drag (compile to activate Angular directives) element.attr('ng-drag', 'true').attr('ng-drag-data', 'event'); $compile(element)($scope); }
5. Clean up your HTML template
Remove the extra ng-repeat inside the calendar container—FullCalendar handles event rendering internally, and this duplicate binding will cause conflicts:
<div> <div id="calendar_one" ng-drop-success="onDropComplete1($data,$event)" ui-calendar="uiConfig.calendar" ng-model="eventSources" calendar="myCalendar"> </div> </div>
Key Notes
- Using decimal values for
sortOrderavoids having to re-number all events when inserting a new one—we just slot the dragged event between existing values. - Always call
rerenderEventsafter updatingsortOrderto tell FullCalendar to refresh the event display. - We use Moment.js to reliably check if events are on the same day.
内容的提问来源于stack exchange,提问作者Venkatesh Mulka

