7
votes

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:

enter image description here

2) I insert a AFTERNOON EVENT (starting at 15:00) and I obtain this correct behavior:

enter image description here

3) I insert now a NIGHT EVENT (from 23:00) and I obtain this absolutly strange behavior:

enter image description here

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?

1
When you tried to debug your application, did you find anything that may explain this behavior? Any console output? Any error messages? Did you try to debug your application??R. Richards
@R.Richards I have not message error into my console...I also tried to debug it but I have no idea about this problem I can only see that it first render the blu background event (the wrong one) into the eventReceive() method and the coorect event into the subscription function. But I have no idea why it happensAndreaNobili

1 Answers

8
votes

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 :-

enter image description here

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.