I am going crazy with a very strange problem that I am facin using PrimeNG FullCalendar component, this one: https://primefaces.org/primeng/showcase/#/fullcalendar
That is based on the Angular FullCalendar component, this one: https://fullcalendar.io/
In particular I am trying to implement a behavior like the last link where draggable event are mooved into the calendar.
Differently from the link example my draggable events have a start and an end time. For example I want drag an evet into a specific day of my calendar specifying that it start at 07:00 and that end at 15:00 (this because my calendar represents a worki shift calendar where put person working in a specific time range).
Here you can find my entire code: https://bitbucket.org/dgs_poste_team/soc_calendar/src/master/
Ok as you can see in the app-component view I have:
<div class="container">
<div class="row">
<div class="col-12">
<app-header></app-header>
</div>
<div class="row">
<div class="col-4">
<p>DRAGGABLE</p>
<app-people-list></app-people-list>
</div>
<div class="col-8">
<app-fullcalendar></app-fullcalendar>
</div>
</div>
</div>
</div>
On the left there is the <app-people-list>
component showing the list of event\people that I can drag into my calendar for a specific work shift.
On the right side I have the <app-fullcalendar>
component rendering my calendar.
Into the PeopleListComponent
class (the controller of the app-people-list
component) I have this ngAfterViewInit
method:
ngAfterViewInit() {
console.log("PEOPLE LIST ngAfterViewInit() START !!!")
var self = this
new Draggable(this.draggablePeopleExternalElement.nativeElement, {
itemSelector: '.fc-event',
eventData: function(eventEl) {
console.log("DRAG !!!");
console.log("SELECTED SHIFT: " + self.selectedShift.value);
//var returnedEvent = self.createEventObject(self.selectedShift.value, eventEl.innerText);
//return returnedEvent;
var returnedEvent = {
title: eventEl.innerText,
startTime: "18:00",
duration: {
hours: 8
}
};
return returnedEvent;
}
});
}
As you can see it is creating a Draggable
object used to drag an event\person of my list into the calendar. At the moment it is returning an object like this:
var returnedEvent = {
title: eventEl.innerText,
startTime: "18:00",
duration: { hours: 8 }
};
where I put the title of the person\event (it works fine). Then I put (at the moment it is static, then I will make it dynamic) the startTime
that is starting time of the event (for example: I drag the person\event into a specific day, it means that this event have to start at the 18:00 of the day in which the event was dragged) and the duration
meaning that the event end 8 hours after the starting time.
Ok, in this case it seems to works "fine", in fact when I drag a person\event into a specific day it appears in the calendar, here is a Screenshot:
For example in the previous screenshot I dragged the PERSONA 2 event into the day having date 22 Februrary 2017 and it is here (the other events came from a static array of events defined into my code)
First strange thing noticed: I expected that thus event starts with something that indicates the starting time (as for the events set for the 9 February that starts with 4p indicating that this event starts at 16:00 o'clock of this specific day).
Ok then the very strange thing: if I change the startTime property of my returnedEvent object with a value that is less than 16:00 it doesn't work anymore !!!
For example, using:
var returnedEvent = {
title: eventEl.innerText,
startTime: "16:00",
duration: {hours: 8}
};
that means: the event start at 4pm of the selected day in the calendar and end at 00:00 of the same day. When I drag this event into the calendar the event doesn't appear on the calendar. It is not rendered !!! It happens for all the startTime
previous 17:00, and I can't understand why. Into the JavaScript console I am obtaining no error message.
For completeness, into the FullcalendarComponent
class (the class that controll the full calendar component) I have:
@Component({
selector: 'app-fullcalendar',
templateUrl: './fullcalendar.component.html',
styleUrls: ['./fullcalendar.component.css']
})
export class FullcalendarComponent implements OnInit {
events: any[];
options: any;
header: any;
//people: any[];
@ViewChild('fullcalendar') fullcalendar: FullCalendar;
constructor(private eventService: EventService) {}
ngOnInit() {
this.eventService.getEvents().then(events => {
this.events = events;
});
this.options = {
plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin, listPlugin],
defaultDate: '2017-02-01',
header: {
left: 'prev,next',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
editable: true,
dateClick: (dateClickEvent) => { // <-- add the callback here as one of the properties of `options`
console.log("DATE CLICKED !!!");
},
eventClick: (eventClickEvent) => {
console.log("EVENT CLICKED !!!");
},
eventDragStop: (eventDragStopEvent) => {
console.log("EVENT DRAG STOP !!!");
},
eventReceive: (eventReceiveEvent) => {
//console.log("EXTERNAL EVENT LAND ON THE CALENDAR. Title: " + eventReceiveEvent.event.title + " Selected shift: " + eventReceiveEvent.selectedShift);
//console.log("EXTERNAL EVENT LAND ON THE CALENDAR. Title: " + eventReceiveEvent.event.title + " Selected start: " + eventReceiveEvent.event.start);
console.log(eventReceiveEvent);
this.eventService.addEvent(eventReceiveEvent);
}
};
}
}
As you can see it contains this method:
eventReceive: (eventReceiveEvent) => {
//console.log("EXTERNAL EVENT LAND ON THE CALENDAR. Title: " + eventReceiveEvent.event.title + " Selected shift: " + eventReceiveEvent.selectedShift);
//console.log("EXTERNAL EVENT LAND ON THE CALENDAR. Title: " + eventReceiveEvent.event.title + " Selected start: " + eventReceiveEvent.event.start);
console.log(eventReceiveEvent);
this.eventService.addEvent(eventReceiveEvent);
}
that receive the previous event emitted by the people list component and put this event into an array (calling a service), it works fine.
I am really not understanding what could be wrong with my code and why using a startTime
value < "17:00" it is not working.
What is wrong? What am I missing? How can I change my code to solve this issue?
When dragging an event into a dayGridMonth
view, FullCalendar doesn't respect allDay
value set in original event definition and always sets allDay: true
. That means, by default, events dragged into a dayGridMonth
view are considered/supposed to be all-day events.
However, when you create a timed event with startTime
and duration
set, that event is not an all-day event any more. And when you drag such an event into a dayGridMonth
view FullCalendar doesn't allow to drop that event into the view.
What you describe as strangest thing is that, when you create following event;
var returnedEvent = {
title: eventEl.innerText,
startTime: "16:00",
duration: {hours: 8}
};
this events end time is after today and FullCalendar considers this as an all-day event. And since this is an all-day event it is allowed to drop it into an all-day slot.
However, when you create following event;
var returnedEvent = {
title: eventEl.innerText,
startTime: "15:00",
duration: {hours: 8}
};
this events end time is today and FullCalendar considers this not as an all-day event but a timed event. And since this is not an all-day event it is not allowed to drop it into an all-day slot.
You can observe same behavior by switching to week or day views and try dropping events into the all-day row at the top. It doesn't allow to drop timed-events into that row while it allows to drop timed-events into any other row.
As a result; you need a way to workaround for FullCalendar to allow timed events to be dropped into an all-day slot. Simple as said :) it is enough to convert all-day events into timed-events after events are parsed by FullCalendar. This can be done in eventReceive
callback.
eventReceive: receivedEvent => {
receivedEvent.event.setAllDay(false, {maintainDuration: true})
}
Long story short, in your FullcalendarComponent
;
eventReceive: (eventReceiveEvent) => {
//console.log("EXTERNAL EVENT LAND ON THE CALENDAR. Title: " + eventReceiveEvent.event.title + " Selected shift: " + eventReceiveEvent.selectedShift);
//console.log("EXTERNAL EVENT LAND ON THE CALENDAR. Title: " + eventReceiveEvent.event.title + " Selected start: " + eventReceiveEvent.event.start);
//console.log(eventReceiveEvent);
eventReceiveEvent.event.setAllDay(false, {maintainDuration: true})
this.eventService.addEvent(eventReceiveEvent);
}
But beware that this will affect all dragged events. So, you might want to set all-day to false based on a condition that can be determined by some flag defined during initial event creation. This very much depends on your use case.
Related docs:
https://fullcalendar.io/docs/eventReceive
https://fullcalendar.io/docs/external-dragging
https://fullcalendar.io/docs/event-parsing
https://fullcalendar.io/docs/Event-setAllDay
https://fullcalendar.io/docs/allDayMaintainDuration
I hope it helps, good luck.