5
votes

I need to be able to set a "date range" with FullCalendar, using the "List" view. By date range, I mean being able to enter using 2 text fields, 2 different dates, for example :

Text field 1 : 2018-05-05

to

Text field 2 : 2018-05-06

And to filter the content of the calendar, using the List view to display the result, and show events that matches that date range.

Here's my code for the FullCalendar part:

 $('#calendar').fullCalendar({
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'listMonth, month,agendaWeek,agendaDay'
      },
      defaultView: 'listMonth',
      locale: 'fr',
      contentHeight: 600,
      navLinks: true, // can click day/week names to navigate views
      selectable: false,
      eventRender: function(event, element, view) { 
        element.find('.fc-widget-header').append("<div style='color:#fff'>Conférencier choisi</div>");
        element.find('.fc-title').append("<br/>" + event.lieu); 
        element.find('.fc-list-item-title').append("<br/>" + event.lieu); 
        element.find('.fc-list-item-title').append("<a href='" + event.lienconferencier + "'><div class='conferencier-calendrier-container'><div style='float:left;background-image:url(" + event.photoconferencier + ");width:40px;height:40px;background-size:cover;border-radius:100px;'></div><div style='float:left;padding-left:5px;font-weight:normal;'><strong>Conférencier</strong><br>" + event.conferencier + "</div></a>"); 
          return ['all', event.status].indexOf($('#filter-status').val()) >= 0 &&
             ['all', event.client].indexOf($('#filter-contact').val()) >= 0 && 
             ['all', event.conferencier].indexOf($('#filter-conferencier').val()) >= 0 &&
             ['', event.numero].indexOf($('#numero').val()) >= 0;

      },
      selectHelper: true,
      editable: false,
      eventLimit: true, // allow "more" link when too many events
      events: [
        {
          title: 'Example',
          start: '2018-05-05',
          end: '2018-05-06',
          color: '#ff0000',
          lieu: 'Montreal',
          numero: '300445',
          conferencier: 'John Doe',
          photoconferencier: 'http://www.example.com/img/profile.jpg',
          lienconferencier: 'http://www.example.com/profile/link.html',
          url: 'http://www.google.com'
        },
{
          title: 'Example2',
          start: '2018-05-08',
          end: '2018-05-010',
          color: '#ff0000',
          lieu: 'New York',
          numero: '300446',
          conferencier: 'Steve Jobs',
          photoconferencier: 'http://www.example.com/img/profile2.jpg',
          lienconferencier: 'http://www.example.com/profile/link2.html',
          url: 'http://www.apple.com'
        },
      ],
    });

And here's my text fields code:

<input type="text" placeholder="Date : From" id="start_date">
<input type="text" placeholder="Date : To" id="end_date">

I think I would have to add something like this:

$('#start_date').on('change', function () {
                $('#calendar').fullCalendar('rerenderEvents');
            });
$('#end_date').on('change', function () {
                $('#calendar').fullCalendar('rerenderEvents');
            });

But I am not sure. Also, please keep in mind that there's other filters too. Hence the "eventRender" part in the code with a bunch of stuff. So I need to make sure that "dateRange" filter won't break the other filters.

I read about "visibleRange" on FullCalendar's website, but I do not understand how I can make it work based on what is entered in the 2 "date range" text fields. I think also disabling the other views that I have set (to show the result in the List view only), would be a good idea.

Any idea how I can make it work? I'm kind of lost here. Thanks a lot


EDIT :

I have tried this code:

$('#start_date').on('change', function () {
      $('#calendar').fullCalendar('changeView', 'list', {
        start: 2018-05-10,
        end: 2018-05-30
      });            
});

Which is working. Basically, what it does is that I enter a new date in a text field with the ID of "start_date" (which uses a datepicker script, to that's why I went with "on change"), it changes the view to the list view, which is great, and displays only the events between the date I have entered. So to make it dynamic, I did this :

$('#start_date').on('change', function () {
  var start_date = $('#start_date').val();
  var end_date = $('#end_date').val();
      $('#calendar').fullCalendar('changeView', 'list', {
        start: start_date,
        end: end_date
      });            
});

I have 2 fields, "start_date", and "end_date". I thought that setting the "start" and "end" option in the changeView code for FullCalendar would update automatically everytime I select a new date, but it doesn't work. In fact, it works partially. If I enter the "end_date" first, then the "start_date", it will filter and work perfectly, showing the right date range. But after that, I cannot change it for another dateRange by changing the dates in the fields. It acts like this probably because my function is "on change", based on the "#start_date" element. So I have to select the end_date first, to make sure it filters and change the view with something in the "end" option.

Any idea what I am doing wrong?

Thanks


EDIT 2 :

I tried changing the function from a "change" event to "click", and adding a "search" button. There's 2 issues here. 1 - It works only once. If I make a search, then change the date, and click again on the "#search-range" button, it won't do anything.

2 - When it works (first time after page load), if I select from May 1rst to May 5th for example, it will show the range from May 1rst to May 4th, for some reasons. Here's my code again :

$('#search-range').on('click', function () {
  var start_date = $('#start_date').val();
  var end_date = $('#end_date').val();
  $('#calendar').fullCalendar('changeView', 'list', {
        start: start_date,
        end: end_date
      });            
});

Any ideas what's going on? Thanks again

1
Have you tried using the "option" method fullcalendar.io/docs/dynamic-options to set the visibleRange property dynamically from your "change" events? You might also have to set your default view to "list" rather than specifically "listMonth", so it doesn't have a time period pre-defined. Both of those things are documented at fullcalendar.io/docs/visibleRange). I haven't tested it, and I don't have time right now, but please try it and let me know.ADyson
If you have a dynamically defined "events" property (e.g. set as a URL or function, not a static JS array), then I think that changing the visible range will automatically cause it to refetch events automatically from the server, and give the server the start and end dates of the newly defined date range, so it can return the correct event information. So you shouldn't need to call refetchEvents manually I don't think - again, you can test it.ADyson
And you can make the other views unavailable simply by changing what buttons are listed in your "header" option.ADyson
Thanks for the help. I managed to partially make it work with "changeView". I have edited my first post (see the "EDIT" section). Any idea how to fix my remaining issue? Thanks!larin555
simply add a search icon in front of the input fields and handle the event range by onclick of that buttonElyas Esna

1 Answers

3
votes

You're probably looking for the validRange option.

$('#start_date').on('change', function(){
  $('#calendar').fullCalendar('option', 'validRange', {
    // Don't worry if user didn't provide *any* inputs.
    start: this.value,
    end: $('#end_date').val()
  });
});

$('#end_date').on('change', function(){
  $('#calendar').fullCalendar('option', 'validRange', {
    // Don't worry if user didn't provide *any* inputs.
    start: $('#start_date').val(),
    end: this.value
  });
});

Demo: https://jsfiddle.net/8wd7sxyv/

UPDATE

  • The end date is now inclusive. So if end date is 2018-05-31, events on that day are included — the default behavior only includes up to 2018-05-30.
  • If the start and end dates are in same month, view is listMonth; otherwise, it is listYear.
  • function filterByDateRange(start_date, end_date, format) {
      var s = $.fullCalendar.moment(start_date),
          e = $.fullCalendar.moment(end_date),
          v = $('#calendar').fullCalendar('getView'),
          a, b;
    
      // Start date is invalid; set it to the start of the month.
      if (! s.isValid()) {
        b = e.isValid();
        s = b ? e.clone() : $.fullCalendar.moment();
        s.date(1);
        $('#start_date').val(s.format(format));
        a = true;
      }
      // End date is invalid; set it to the end of the month.
      if (! e.isValid()) {
        b = s.isValid();
        e = b ? s.clone() : $.fullCalendar.moment();
        e.date(e.daysInMonth());
        $('#end_date').val(e.format(format));
        a = true;
      }
    
      // Start date is after end date; set it to a day before the end date.
      if (s.isAfter(e)) {
        s = e.clone().add('-1', 'day');
        $('#start_date').val(s.format(format));
      // End date is before start date; set it to a day after the start date.
      } else if (e.isBefore(s)) {
        e = s.clone().add('1', 'day');
        $('#end_date').val(e.format(format));
      }
    
      // Add 1 day so that `end_date` is inclusive.
      e = e.isValid() ? e.add('1', 'day') : e;
    
      $('#calendar').fullCalendar('option', 'validRange', {
        start: s.isValid() ? s : null,
        end: e.isValid() ? e : null
      });
    
      a = a || s.isSame(e, 'month');
      // If months are different, switch to the year list.
      if ('listYear' !== v.name && ! a) {
        $('#calendar').fullCalendar('changeView', 'listYear');
      // Otherwise, switch back to month list, if needed.
      } else if ('listMonth' !== v.name) {
        $('#calendar').fullCalendar('changeView', 'listMonth');
      }
    }
    
    $('#start_date').on('change', function(){
      filterByDateRange(this.value, $('#end_date').val(), 'YYYY-MM-DD');
    });
    
    $('#end_date').on('change', function(){
      filterByDateRange($('#start_date').val(), this.value, 'YYYY-MM-DD');
    });
    

    Demo: https://jsfiddle.net/8wd7sxyv/6/