Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I dynamically delete events from this PrimeNG FullCalendar (clicking on an event)?

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/

So I have a calendar like this:

enter image description here

What I am trying to implement at this stage is that when the user click on a specific event, all the events into this calendar will be deleted (in a second stage I will implement that only the specific clicked event will be deleted, but at the moment I am keeping the logic as simple as possible).

So this is the class controlling my calendar 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;

  calendar:any;


  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');

      //let events = this.calendar.getEvents();
      //events[

      console.log("EVENTS: " + this.events);

      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 !!!");
          console.log(eventClickEvent.event.id);
          //this.eventService.removeEventById(eventClickEvent.event.id);
          this.eventService.removeEventById(eventClickEvent.event.id).subscribe(events => console.log(events));


            /*
            events => { this.events = events.map((event) => {
            var date = new Date(event.start);
            var hour = date.getHours();

            console.log("EVENTS: " + this.events);

            if(hour === 7) {
              event['backgroundColor'] = 'red';
            }
            else if(hour === 15) {
              event['backgroundColor'] = 'green';
            }
            else if(hour === 23) {
              event['backgroundColor'] = 'black';
            }

            return event;
          })});
          */
        },

        eventDragStop: (eventDragStopEvent) => {
          console.log("EVENT DRAG STOP !!!");
        },

        eventReceive: (eventReceiveEvent) => {
          console.log(eventReceiveEvent);
          //eventReceiveEvent.event.setAllDay(false, {maintainDuration: true});



          //eventReceiveEvent['backgroundColor'] = 'red';
          this.eventService.addEvent(eventReceiveEvent);
        }
    };

  }

  ngAfterViewInit() {

    this.calendar = this.fullcalendar.getCalendar();
    console.log("CALENDAR: " + this.calendar);

  }

}

As you can see into the ngOnInit() method I am subscribing the getEvents() method of a service that return the list of rendered events as Observable (I am doing in this way because in the returned output I am handling different color for different events type, but this is not strictly related to my question...it works fine).

So, as you can see this component class contains this hook method eventClick: (eventClickEvent) handling the click on an event of my calendar. I was thinking to call a delete events method defined into my service and render it again but it is not working (I have done several try and it is not working). I am also not sure that this is the correct approach to the problem.

From what I can understand into the ngOnInit() method I have the subscription to my calendar event array, so chainging the content of this array this change is published and it should rendered again, I tried also this but it is not working...so I think that probably I am missing something in the Angular logic.

This is the code of my service class:

import { Injectable } from '@angular/core';
import { HttpClientModule, HttpClient } from '@angular/common/http'
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable()
export class EventService {

  private events = [];

  /*
  private events = [
    {id: 1, title: 'All Day Event', start: '2017-02-01'},
    {id: 2, title: 'Long Event', start: '2017-02-07', end: '2017-02-10'},
    {id: 3, title: 'Repeating Event', start: '2017-02-09T16:00:00'},
    {id: 3, title: 'test', start: '2017-02-20T07:00:00'},
  ];
  */

  private people = [
    {id: 1, name: "PERSONA 1"},
    {id: 2, name: "PERSONA 2"},
    {id: 3, name: "PERSONA 3"},
    {id: 4, name: "PERSONA 4"},
    {id: 5, name: "PERSONA 5"},
  ]

  public eventData = new BehaviorSubject(this.events);

  constructor(private http: HttpClient) {}

  getEvents(): Observable<any[]> {
    return this.eventData.asObservable();
  }


  addEvent(event) {
    //console.log(event.event.start);
    //console.log(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]);
    //console.log(this.events);
  }

  removeEventById(id:number): Observable<any[]>  {
    console.log("EVENTDATA: " + this.eventData.getValue());

    return this.eventData.asObservable();
  }


  /*
  removeEventById = (id:number) => {
    this.events = [];
    //return this.events.filter(each=>each.id!=id);

  }
  */

  getPeople(): Promise<any[]> {
    return Promise.all(this.people)
        .then(res => {
          console.log(res);
          return res;
        })
  }

}

So what is wrong? What am I missing? What could be a smart solution to correctly handle my problem?

like image 570
AndreaNobili Avatar asked Jun 04 '20 16:06

AndreaNobili


2 Answers

primeng fullcalendar developed from fullcalendar.io, you can filter data then assign to eventData. I created your code in Demo

 this.eventService.removeEventById(eventClickEvent.event.id).subscribe(events => console.log(events));

in your method

removeEventById(id:number): Observable<any[]>  {
    this.events=this.events.filter(each=>each.id!=id);
    this.eventData.next([...this.events]);
    return this.eventData.asObservable();
}
like image 93
mr. pc_coder Avatar answered Oct 19 '22 10:10

mr. pc_coder


As you are using Observables, you can use the map operator combined with Array.prototype.filter:

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

removeEventById(id:number): Observable<any[]>  {    
    return this.getEvents()
        .pipe(
            map(items => items.filter(item => item.id == id))
        );    
} 

The whole work example can be seen at the stackblitz.

So your service could look like this:

@Injectable()
export class MyServices {
    private events = [
        {   
          id: 1,
          title: 'Foo 1',
          date: '2020-06-07'
        },
        {
          id: 2,
          title: 'Foo 2',
          date: '2020-06-08'
        },
        {
          id: 3,
          title: 'Foo 3',
          date: '2020-06-05'
        }
    ];

    public eventData = new BehaviorSubject(this.events);

    constructor() { }

    sayHello() {        
        console.log("Say Hello");
    }

    getEvents(): Observable<any[]> {
        return this.eventData.asObservable();
    }


  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(Object.assign({}, this.events));
  }

  removeEventById(id:number): Observable<any[]>  {    
    return this.getEvents()
      .pipe(
        map(items => items.filter(item => item.id == id))
      );    
  }    
}

and your.component.ts could look like this:

export class AppComponent implements OnInit {
    options: any;
    eventsModel: any;
    @ViewChild('fullcalendar') fullcalendar: FullCalendarComponent;
    @ViewChild('external') external: ElementRef;

    constructor(private myServices: MyServices){
        this.myServices.sayHello();
    }

    eventClick(model) {
        this.myServices.removeEventById(model.id)
            .subscribe(s => this.eventsModel = s);       
    }
like image 23
StepUp Avatar answered Oct 19 '22 10:10

StepUp