I am working on an Angular application using PrimeNG Full Calendar component, this one: https://primefaces.org/primeng/showcase/#/fullcalendar
That is based on the Angular FullCalendar component, this one: https://fullcalendar.io/
Here you can find my entire code: https://bitbucket.org/dgs_poste_team/soc_calendar/src/master/
I am finding some difficulties trying to dinamically change the background color of the event rendered on my calendar. I have to have different event background color based on different event information (the start event time, for example: if an event start at 07:00 is green, if it start at 15:00 it is red, if it start at 23:00 it is blue, but this logic is not important at this time).
In my project I am dragging external event into my calendar, something like this: https://fullcalendar.io/docs/external-dragging-demo
So, as you can see in my BitBucket repository I have this FullcalendarComponent handling the component that contains the calendar that recives events from an external component:
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { EventService } from '../event.service';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import listPlugin from '@fullcalendar/list';
import interactionPlugin, { Draggable } from '@fullcalendar/interaction';
import { FullCalendar } from 'primeng';
@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.eventService.getEvents().subscribe(events => { this.events = events.map((event) => {
var date = new Date(event.start);
var hour = date.getHours();
//event['backgroundColor'] = hour === 7? 'red': (hour === 7 ? 'green' : 'black');
if(hour === 7) {
event['backgroundColor'] = 'red';
}
else if(hour === 15) {
event['backgroundColor'] = 'green';
}
else if(hour === 23) {
event['backgroundColor'] = 'black';
}
return event;
})});
this.options = {
plugins:[ dayGridPlugin, timeGridPlugin, interactionPlugin, listPlugin ],
defaultDate: '2017-02-01',
header: {
left: 'prev,next',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
editable: true,
nextDayThreshold: '09:00:00',
allDayDefault: false,
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(eventReceiveEvent);
//eventReceiveEvent.event.setAllDay(false, {maintainDuration: true});
this.eventService.addEvent(eventReceiveEvent);
}
};
}
}
As you can see this object contains the eventReceive() method listening for the drag and drop event. So I can drag an object from a list event component into this calendar. At the moment I have commented out this line:
eventReceiveEvent.event.setAllDay(false, {maintainDuration: true});
to avoid event duplication in my calendar (I will explain this soon). So the when an event is dragged into my calendar it is inserted into an array of events by this service method:
addEvent(event) {
const newEvent = {id: 5, title: event.event.title, start: event.event.start, end: event.event.end};
this.events.push(newEvent);
this.eventData.next([...this.events]);
}
where eventData is defined as BehaviorSubject into my service class, in this way:
public eventData = new BehaviorSubject(this.events);
To show the event on the calendar I am using this approach (instead use the eventReceiveEvent.event.setAllDay(false, {maintainDuration: true}); because to make this color decision automatic whenever a event is added I do: whenever I will push new event through my addEvent() method of service --> my subscription in ngoninit of component will receive updated data and apply background colors displaying the event with the right color.
Ok it seems to works fine excetp the night use case (hour value equal to 23).
Here a printscreen showing the problem:
1) I insert a MORNING EVENT (starting at 07:00) and I obtain this correct behavior:
2) I insert a AFTERNOON EVENT (starting at 15:00) and I obtain this correct behavior:
3) I insert now a NIGHT EVENT (from 23:00) and I obtain this absolutly strange behavior:
As you can see the problem is that the event is dublicated, in particualar:
The BLACK background event was correctly added into the subscription function defined into the ngOnInit() (this is the correct one).
The BLUE background event (that have not to be added) is added by:
eventReceive: (eventReceiveEvent) => {
console.log(eventReceiveEvent);
//eventReceiveEvent.event.setAllDay(false, {maintainDuration: true});
this.eventService.addEvent(eventReceiveEvent);
}
And I can't understand why !!! At the beginning of the post I say that I removed this line from the **eventReceive() method:
eventReceiveEvent.event.setAllDay(false, {maintainDuration: true});
this because, if enabled, also the morning and afternoon event will have the same duplication behavior.
What is the problem? What is wrong with my code? How can I try to fix it?
Resolved the issue :-
Update your addEvent method to :-
addEvent(event) {
console.log(event.event.end);
const newEvent = {id: 5, title: event.event.title, start: event.event.start, end: event.event.end};
event.event.remove();
this.events.push(newEvent);
this.eventData.next([...this.events]);
}
I have added a call to remove the dropped event. Got the reference of remove method from :- https://fullcalendar.io/docs/Event-remove
Adding screenshot to show, that it works :-
Reason of issue :- in this case there became two duplicate events, because when you started at any time with duration of 2 hours which ended up from current date to next date and pushed it into events array. these two became different events in this case. because dropped one was having different attributes then newly created one. which didn't happen in other cases.
After above solution even if you keep
eventReceiveEvent.event.setAllDay(false, {maintainDuration: true});
as uncommented, it will not lead to issue. because everytime my code will remove dropped event and because we are pushing new event to events array, only pushed one will display. dropped one will be removed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With