Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select and move/edit multiple events #2253

Open
arshaw opened this issue Aug 19, 2015 · 31 comments
Open

Select and move/edit multiple events #2253

arshaw opened this issue Aug 19, 2015 · 31 comments

Comments

@arshaw
Copy link
Member

arshaw commented Aug 19, 2015

Originally reported on Google Code with ID 1988

User Stories:
- select events across days in a time-slot and move them to a new time-slot and/or
day
- select events across time-slots in a day and move them to a new time-slot and/or
day
- select discontiguous events and move them to different time-slots and/or days

Additional Requirements:
- selections should move as a relative group, for example, selecting and moving events
(mon8am and tue9am) to (thu7am and fri8am), respectively
- visual indicators should suggest where the events will drop
- selections should adhear to the snapping to grid features
- selections should be initiated with the shift-key on drag or the alt-key on click
- selections should not be able to move beyond the visible calendar time-slots and/or
days, for example, - selecting and moving events (mon and tue) to (sat and sun), respectively
is not permitted in a calendar view showing days sun,mon,tue,wed,thu,fri,sat

Reported by doug@onvelocity.com on 2013-09-04 13:29:08

Imported with 13 stars

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

how would you imagine the user actually makes the selection? would they click there
mouse down and draw a rectangle, causing all intersecting events to be selected?

Reported by adamrshaw on 2013-09-14 06:06:58

  • Status changed: Discussing
  • Labels added: Type-Feature

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

> how would you imagine the user actually makes the selection? would they click there
mouse down and draw a rectangle, causing all intersecting events to be selected?

Yes. jQuery selectable has the lasso behavior already (discovered only after implementing
one). Getting FullCalendar to support multiple event editing is the real work. 

I'm currently implementing in a fork, if you like to see my approach: https://github.com/javadoug/fullcalendar/tree/issue_1988/select-events.


The demos/selectable.html allows you to see this new functionality. I've got editing
inside the calendar working. Am working on adding ability to drop external events onto
the calendar now. 

Note: my fork changes are targeting the needs of one client, so I would need to do
more testing to ensure all of FC is supported. For example, right now you can drag
multiple from all-day bar into the time-slot area, which is not ideal user interaction.
I would want to disable that. But since my client does not use all-day bar, that task
is pending.

As always, I'm glad to help anyway I can. If you find changes in my fork that you need/want
me to make in order to consider my fork - I'm glad to do it (if I can). Otherwise,
of course, feel free to copy what you need if you decide to add this feature.

Reported by doug@onvelocity.com on 2013-11-04 19:25:22

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

Hi, i see last post was some months ago, i just want to know if this feature is working/tested.
I'm looking for a solution to select and move a group of events at the same time.

Thanks.

Reported by ignaciotricherri on 2014-04-28 16:42:14

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

@ignaciot Yes, in my fork there is a branch that has this code working (we use it in
a production system) and it has tests, etc. See my previous comment. Note that this
feature branch is not up to date with the current version of FC. Due to our needs we
have not been keeping it up to date. 

Reported by doug@onvelocity.com on 2014-05-23 00:13:30

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

Issue 2357 has been merged into this issue.

Reported by adamrshaw on 2014-06-07 21:46:36

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

Issue 2326 has been merged into this issue.

Reported by adamrshaw on 2014-06-07 21:46:46

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

Reported by adamrshaw on 2014-06-07 21:46:59

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

It would also be nice if you could search for all events "newer than 01 Jan 1980" and
then move the result to a different calendar.

Reported by dbonde on 2014-09-03 12:03:45

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

This feature is not about "searching". It is about "lasso-ing" with a mouse or other
selection affordances. Please do not merge search in to this one. thanks.

Reported by doug@onvelocity.com on 2014-09-03 12:11:22

@arshaw
Copy link
Member Author

arshaw commented Aug 19, 2015

Issue 2745 has been merged into this issue.

Reported by adamrshaw on 2015-04-20 03:32:16

@TomLynchTM
Copy link

Is this feature still being worked on? I am planning to implement the scheduler version of fullcalendar and one of my requirements is moving and re-sizing multiple events simultaneously. I am trying to decide if I should come up with a specific solution to my problem or if this will be part of the base tool at some point. Thanks for any insight you can provide. Great tool by the way, it's been very simple to implement but provides outstanding hooks to the various events to implement custom functionality easily.

@alex-barberi
Copy link

I really need this multi-select feature. I need to be able to select multiple calendar events and drag all of the selected calendar events at the same time.

@glagola
Copy link

glagola commented Feb 3, 2016

Any progress? I really need this multi-select feature.

@espen
Copy link
Contributor

espen commented Feb 3, 2016

FullCalendar is an open source project. Feel free to make a pull request. See http://fullcalendar.io/wiki/Contributing/

@alex-barberi
Copy link

Here's how I ended up doing the multi-select; I added checkboxes to each calendar item. This is a working multi-select feature. I'm using it in a production website. FYI - This does not do any lassoing. Again, it relies on checkboxes. Also, this moves the items on the calendar and sends the update to the server without doing a page refresh. @TomLynchTM @glagola

With this method (below), the user must check the box on each calendar item and then move one of the calendar items to the desired date. After moving one item, all the other checked calendar items will be moved to the new date as well.

$('#calendar').fullCalendar({
    events: data,
    header: {
        left: 'prev,next today',
        center: 'title',
        right: 'month,basicWeek,basicDay'
    },
    editable: true,
    droppable: true,
    selectable: true,
    eventDrop: saveDragDropChanges,
    eventRender: function (event, element, view) {
        $('<input />', { type: 'checkbox', id: 'cb' + event.id, value: event.id }).appendTo(element);
    }
});

function saveDragDropChanges(event, dayDelta, minuteDelta, allDay, revertFunc) {
    if (event == null) return;
    if ($('#calendar input:checked').length <= 0) return;

    var start = event._start;

    var d = start.getDate();
    var m = start.getMonth() + 1;
    var y = start.getFullYear();

    var hours = start.getHours();
    var mins = start.getMinutes();

    var dateJson = ' start: "' + m + '/' + d + '/' + y + ' ' + hours + ':' + mins + '"';

    var listToSend = '';

    $('#calendar input:checked').each(function () {
        $(this).prop("checked", false);

        // find the event on the calendar with $.grep
        var value = $(this).attr('value');
        var result = $.grep($('#calendar').fullCalendar('clientEvents'), function (e) { return e.id == value; });

        var id = String(result[0]._id);
        listToSend += id + ',';

        // move the item on the calendar
        $('#calendar').fullCalendar('clientEvents', result[0]._id)[0].start = start;
        $('#calendar').fullCalendar('clientEvents', result[0]._id)[0].end = start.setHours(start.getHours() + 1);
    });

    // remove trailing comma
    listToSend = listToSend.substr(0, listToSend.length - 1);

    // create json string
    var jsonToSend = '{ idList: "' + listToSend + '",' + dateJson + ' }';

    // send IDs to the server along with the new date
    var jqxhr = $.ajax({
        url: '/Controller/updateCalendarItemMultiple',
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        data: jsonToSend,
        dataType: 'json',
        cache: false,
        async: true
    });

}

@gregblass
Copy link

gregblass commented Dec 7, 2016

I was able to implement my own version of this for a client. I accomplished it basically by assigning a highlighted class to events on click, and modifying the behavior if the user holds down shift.

Dragging and dropping multiple events was challenging. I essentially made a container and cloned the selected events and placed them inside and dragged that - then wrote methods in the drop callback to loop through selected events to add or update calendar event data.

The positioning of events in the cloned container when dragging was fairly challenging too, along with calculating positioning when dropping multiple or updating multiple event time offsets when dragging multiple.

This is, however, all possible though. Personally I didn't have to go as far or as complicated as the fork that was posted above.

@jordan-realfoto
Copy link

+1 for this feature

@thomas-alrek
Copy link

+1 for this feature

@gregblass
Copy link

gregblass commented May 23, 2017

I wish I had time to contribute and add what I did but it was really involved and unfortunately sallie mae owns my soul. Maybe one day I'll try to make a gist.

@alex-barberi
Copy link

@arshaw I recently had a brainstorming session with a client. He wanted to have a button that would "flag" multiselect mode. When in multiselect mode, any click on any event would highlight/select the event. The user would be able to keep selecting events until he moved one of the events to a new day on the calendar. When one of the selected events was moved to a new day, all of the selected events would move to that same day. At this point, the multiselect flag would be cleared.

Just an idea you may be interested in implementing in fullCalendar.

P.S. Not sure how this would work on Day view.

@gregblass
Copy link

@alex-barberi The way I did it was to hold down shift or control.

@alex-barberi
Copy link

@alex-barberi The way I did it was to hold down shift or control.

@gregblass Definitely a good option. However, we found it annoying to hold down CTRL... Then accidentally let go of CTRL and click something, only to lose all your selections.

However, holding down shift or ctrl is still a viable option. From a User Experience perspective, I think there are better options, but holding down Ctrl or Shift was the first thing we thought of doing. And Ctrl or Shift could be good because it is what people are used to doing.

From a developer perspective, I'm not sure about how good of an idea it is to bind to key events in the browser and rely on those events with the calendar, but maybe there is a safe way to do this.

Definitely some unknowns & "scary things" for me here, but it sounds like Ctrl or Shift could still be a good option.

@cptx032
Copy link

cptx032 commented Aug 9, 2017

Has many options for doing the multiple selection. Would be nice if we could choose the better way to do that. Just something like:

{
    multiple_selection: true
}

Then, marking the event with something (a css class?) and, in dragging, the fullcalendar does the magic with the marked ones. Full Calendar just should give us a way/function/option to mark some event, and unselect too. But who marks the events (using the fullcalendar api) is the developer in the way that he thinks best

@arshaw arshaw removed their assignment Nov 30, 2017
@elish77
Copy link

elish77 commented Dec 7, 2018

+1 for this feature
Any news?

@ElectricCarbon
Copy link

+1. Hope to see this in a future version of fullcalendar

@nickmadestories
Copy link

+1 :)

@meijdenmedia
Copy link

+1

@alexgalie
Copy link

I was able to implement my own version of this for a client. I accomplished it basically by assigning a highlighted class to events on click, and modifying the behavior if the user holds down shift.

Dragging and dropping multiple events was challenging. I essentially made a container and cloned the selected events and placed them inside and dragged that - then wrote methods in the drop callback to loop through selected events to add or update calendar event data.

The positioning of events in the cloned container when dragging was fairly challenging too, along with calculating positioning when dropping multiple or updating multiple event time offsets when dragging multiple.

This is, however, all possible though. Personally I didn't have to go as far or as complicated as the fork that was posted above.

I know this is old but I ran into this issue just now. I tried your approach but after adding a class to an event and calling .fullCalendar('update') on it the event cannot be dragged (it dissapears when start dragging). Do you know this issue?

@alexgalie
Copy link

I was able to implement my own version of this for a client. I accomplished it basically by assigning a highlighted class to events on click, and modifying the behavior if the user holds down shift.
Dragging and dropping multiple events was challenging. I essentially made a container and cloned the selected events and placed them inside and dragged that - then wrote methods in the drop callback to loop through selected events to add or update calendar event data.
The positioning of events in the cloned container when dragging was fairly challenging too, along with calculating positioning when dropping multiple or updating multiple event time offsets when dragging multiple.
This is, however, all possible though. Personally I didn't have to go as far or as complicated as the fork that was posted above.

I know this is old but I ran into this issue just now. I tried your approach but after adding a class to an event and calling .fullCalendar('update') on it the event cannot be dragged (it dissapears when start dragging). Do you know this issue?

If anyone runs into this: it was because I was actually using the Ctrl key for selecting. Using shift doesn't cause this bug.

@Glideh
Copy link

Glideh commented Feb 25, 2022

I'm thinking about a quite simple workaround for my most common use case.
Sometimes I need to insert/remove/resize an event on a day already full, and I'd like to be able to move all the following events at once after the one I'm inserting/removing/resizing.
So when I'm moving one event on the same day and for which there are consecutive others, I would show a confirm window asking:

Do you want to move the events following this one accordingly ?

@Glideh
Copy link

Glideh commented Feb 25, 2022

Here is what I'm doing to move the following events if needed:

function sameDay(d1, d2) {
    return d1.getFullYear() === d2.getFullYear() &&
        d1.getMonth() === d2.getMonth() &&
        d1.getDate() === d2.getDate();
}

function moveableNextEvents(currentEvent, events) {
    // Checking if there is an event right after the current one
    if (!events.find(event => event.start.getTime() === currentEvent.end.getTime())) return;
    // Getting the events after the current one in the same day
    const nexts = events.filter(event => {
        return sameDay(event.start, currentEvent.start)
            && event.start.getTime() > currentEvent.start.getTime()
            && event.id !== currentEvent.id
        ;
    });
    if (!nexts.length) return;
    // Asking the user a confirmation if any concerned events have been found
    if (!confirm('Do you want to move the following ' + nexts.length + ' event(s) alongside ?')) return;
    return nexts;
}

function getEventsWithDelta(events, newEvent, oldEvent) {
    const moveableEvents = moveableNextEvents(oldEvent, events, skipConfirm);
    if (!moveableEvents || !moveableEvents.length) return [];
    // Getting the delta from a modified start (move) or end (resize)
    const millisecondsDelta = (newEvent.start.getTime() - oldEvent.start.getTime())
        || (newEvent.end.getTime() - oldEvent.end.getTime())
    moveableEvents.forEach(event => {
        // Using dayjs here to apply the delta but any other can do
        event.start = dayjs(event.start).add(millisecondsDelta, 'ms');
        event.end = dayjs(event.end).add(millisecondsDelta, 'ms');
    });
    return moveableEvents;
}
// I'm updating the events directly here but we might better create new ones

Here how it can be used from eventDrop or eventResize

// fcApi contains the fullCalendar instance
eventDropOrResize({ event, oldEvent }) {
    // Updating the original event
    update(event);
    // Moving all next events if needed
    getEventsWithDelta(fcApi.getEvents(), event, oldEvent).forEach(nextEvent => {
        update(nextEvent);
    });
}

This alternative is fine for my use case, I don't need a more elaborate multiple selection.
Of course this does not answer the multiple edit topic, but it might be good enough for some people.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

No branches or pull requests