javascriptjqueryfullcalendarfullcalendar-6

fullcalendar io 6.1.8 add event filters


I need to add event filtering to my calendar

I added a special select for this and a function for this select that should update the calendar

But I had a problem that this function only works once. Let's say I launch the calendar, select a filter, everything is displayed as it should. But when I try to immediately change the filter to another one, all the events disappear altogether, what’s the problem?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.8/index.global.min.js"></script>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      var calendarEl = document.getElementById('calendar');

      var calendar = new FullCalendar.Calendar(calendarEl, {
        initialView: 'dayGridMonth',
        events: [
          {
            title: 'Event 1',
            start: '2024-01-01',
            dataFilter: 'filter1'
          },
          {
            title: 'Event 2',
            start: '2024-01-02',
            dataFilter: 'filter2'
          },
        ],
        eventClick: function(info) {
          alert('Event: ' + info.event.title);
        },
        headerToolbar: {
          left: 'prev,next today',
          center: 'title',
          right: 'dayGridMonth,timeGridWeek,timeGridDay'
        },
      });

      calendar.render();

      var filterSelect = document.getElementById('filterSelect');

      filterSelect.addEventListener('change', function() {
        var selectedFilter = filterSelect.value;

        var filteredEvents = calendar.getEvents().filter(function(event) {
          return selectedFilter === 'all' || event.extendedProps.dataFilter === selectedFilter;
        });

        calendar.setOption('events', filteredEvents);
      });
    });
  </script>
</head>
<body>
  <label for="filterSelect">Select event:</label>
  <select id="filterSelect">
    <option value="all">All events</option>
    <option value="filter1">Event 1</option>
    <option value="filter2">Event 2</option>
  </select>

  <div id="calendar"></div>
</body>
</html>


Solution

  • A tiny bit of debugging shows that filteredEvents contains one item after you filter by "Event 1" first, and then none any more, when you filter by "Event 2" next. And that in turn is due to the fact, that calendar.getEvents() only returns the already filtered set of events.

    Keep your events in a separate variable outside of the FullCalendar initialization, so that you can use that original data set again when you filter:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.8/index.global.min.js"></script>
      <script>
        let events = [
              {
                title: 'Event 1',
                start: '2024-01-01',
                dataFilter: 'filter1'
              },
              {
                title: 'Event 2',
                start: '2024-01-02',
                dataFilter: 'filter2'
              },
            ];
        document.addEventListener('DOMContentLoaded', function() {
          var calendarEl = document.getElementById('calendar');
    
          var calendar = new FullCalendar.Calendar(calendarEl, {
            initialView: 'dayGridMonth',
            events: events,
            eventClick: function(info) {
              alert('Event: ' + info.event.title);
            },
            headerToolbar: {
              left: 'prev,next today',
              center: 'title',
              right: 'dayGridMonth,timeGridWeek,timeGridDay'
            },
          });
    
          calendar.render();
    
          var filterSelect = document.getElementById('filterSelect');
    
          filterSelect.addEventListener('change', function() {
            var selectedFilter = filterSelect.value;
    
            var filteredEvents = events.filter(function(event) {
              return selectedFilter === 'all' || event.dataFilter === selectedFilter;
            });
    
            calendar.setOption('events', filteredEvents);
          });
        });
      </script>
    </head>
    <body>
      <label for="filterSelect">Select event:</label>
      <select id="filterSelect">
        <option value="all">All events</option>
        <option value="filter1">Event 1</option>
        <option value="filter2">Event 2</option>
      </select>
    
      <div id="calendar"></div>
    </body>
    </html>