Search code examples
javascriptlaravelfullcalendarfullcalendar-4

If FullCalendar 4 shows events only for current month error when loading data from datesRender event?


In my Laravel 8 / jQuery 3.5.1 / bootstrap 4.5.3 app with FullCalendar v4.3.1 I show events only for current month and user can select month by clicking on Next Prior month arrows of the calendar.

I need to retrieve data from db only for selected month. I need to run data retrieve method when user clicks on Next Prior month arrows. I make it with datesRender event, but I got problems that datesRender is triggered again when data retrieved and I got endless triggering of this method.

I do :

jQuery(document).ready(function ($) {

    adExpireDateEvenstLoadWithFullCalendar()  // get data from db for selected month
    ...
}) // jQuery(document).ready(function ($) {

function adExpireDateEvenstLoadWithFullCalendar () { // get data from db for selected month
    var dataArray = {
        '_token': '{{ $csrf_token }}',
        'year': select_year,
        'month': parseInt(select_month) + 1
    }

    var href = "/admin/get_ad_events"
    $.ajax({
        type: "POST",
        dataType: "json",
        url: href,
        data: dataArray,
        success: function (response) {
            initFullCalendar(response.events, response.calendar_events_default_date);
        },
        error: function (error) {
            popupErrorMessage(error.responseJSON.message)
        }
    });

} // function adExpireDateEvenstLoadWithFullCalendar () { // get data from db for selected month

function initFullCalendar(eventsList, calendar_events_default_date) { // init FullCalendar with given array of data and month
    if (typeof window.calendarEventsObject != "undefined") { // clear existing instance
        window.calendarEventsObject.destroy();
    }

    var calendarEl = document.getElementById('expire_date_events_calendar');

    var current_date = moment(calendar_events_default_date).format('YYYY-MM-DD')
    var today = moment();

    window.calendarEventsObject = new FullCalendar.Calendar(calendarEl, { // FullCalendar Init
        plugins: ['dayGrid', 'timeGrid'],
        defaultView: 'dayGridMonth',

        views: {
            dayGridMonth: {
                buttonText: 'Month'
            },
            timeGridWeek: {
                buttonText: 'Week'
            }
        },


        axisFormat: "H:mm A",
        timeFormat: "H:mm A",

        header: {
            left: 'dayGridMonth,timeGridWeek',
            center: 'title',
            right: 'today prev,next '
        },

        eventRender: function (eventInfo) {
            ...
        }, // eventRender: function (eventInfo) {


        dayRender: function (date) {
           ...
        },

        datesRender: function (view) {
            select_year= view.view.currentStart.getFullYear()
            select_month= view.view.currentStart.getMonth()
            if (calendarExpireDateEventsObject) {
                calendarExpireDateEventsObject.datepicker('setDate', new Date(select_year, select_month, 1)).trigger('change');
                adExpireDateEvenstLoadWithFullCalendar() // I need to read data for selected month and THIS RAISE endless triggering of this method

            }
        }, // datesRender

        select: function (start, end, allDay) {
            ...
        },

        events: eventsList,
        defaultDate: current_date,
        showNonCurrentDates: false,
        displayEventTime: true,
        eventLimit: true, // allow "more" link when too many events

        editable: true,
        allDaySlot: true,
        selectable: true,
        selectHelper: true,
        selectOverlap: false,
        fixedWeekCount: false,
        disableDragging: true,

        aspectRatio: 0.4,
        height: 900,
        eventClick: function (clickObj) {
            ...
            return false;
        },
    });  // window.calendarEventsObject = new FullCalendar.Calendar(calendarEl, { // FullCalendar Init
    //    'calendar_events_default_date' => '2019-08-22',

    window.calendarEventsObject.render(
        {
            backgroundColor: 'green',
            textColor: 'yellow',
        }
    );

    jQuery('.eo-fullcalendar').on('click', '.fc-event', function (e) {
        e.preventDefault();
        ...
    });

}   // function initFullCalendar(eventsList, calendar_events_default_date) { // init FullCalendar with given array of data and month

Any hints how that can be fixed ?

MODIFIED BLOCK : I found this https://fullcalendar.io/docs/v4/events-function page and try to use it in my blade page :

@section('scripts')

<link rel="stylesheet" href="{{ asset('/css/fullcalendar/core/main.css') }}" type="text/css">
<link rel="stylesheet" href="{{ asset('/css/fullcalendar/daygrid/main.css') }}" type="text/css">
<link rel="stylesheet" href="{{ asset('/css/fullcalendar/timegrid/main.css') }}" type="text/css">

<link href="{{ asset('css/gijgo.min.css') }}" rel="stylesheet" type="text/css">
<link href="{{ asset('css/jquery-ui.css') }}" rel="stylesheet" type="text/css">

<script src="{{ asset('js/moment.min.js') }}"></script>
<script src="{{ asset('js/popper.min.js') }}"></script>
<script src="{{ asset('js/bootstrap.min.js') }}"></script>


<script src="{{ asset('js/fullcalendar/core/main.js') }}"></script>
<script src="{{ asset('js/fullcalendar/daygrid/main.js') }}"></script>
<script src="{{ asset('js/fullcalendar/timegrid/main.js') }}"></script>


<script src="{{ url('js/jquery-ui.min.js') }}"></script>

<script>

    let select_year = '{{ $select_year }}'
    let select_month = '{{ $select_month }}'
    let calendarExpireDateEventsObject = null
    
    jQuery(document).ready(function ($) {
        backendInit('list', 'expire_date_events_calendar')
        // fullCalendarInit()
        console.log('BEFORE::')
        // import { req } from 'superagent'; // ajax library

        var calendar = new Calendar(calendarEl, {

            events: function(info, successCallback, failureCallback) {

                req.get('myxmlfeed.php')
                    .type('xml')
                    .query({
                        start: info.start.valueOf(),
                        end: info.end.valueOf()
                    })
                    .end(function(err, res) {

                        if (err) {
                            failureCallback(err);
                        } else {

                            successCallback(
                                Array.prototype.slice.call( // convert to array
                                    res.getElementsByTagName('event')
                                ).map(function(eventEl) {
                                    return {
                                        title: eventEl.getAttribute('title'),
                                        start: eventEl.getAttribute('start')
                                    }
                                })
                            )
                        }
                    })

            }

        });

and I got error in the console :

jquery.min.js:2 Uncaught ReferenceError: Calendar is not defined
    at HTMLDocument.<anonymous> 

Maybe I missed some .js files ? included list of files worked ok for my priorcode... All files v4.3.0.

Thanks!


Solution

  • You said

    I need to run data retrieve method when user clicks on Next Prior month arrows

    ...but actually no, you don't. You need to follow the proper system for doing this which fullCalendar has provided. See https://fullcalendar.io/docs/v4/events-function . If you give fullCalendar a callback function which runs your AJAX request, it will automatically call that function whenever it needs new events (i.e. whenever the date range being displayed changes). It passes the current start/end dates into the function so that you can use them in your AJAX to send to the server. No need to mess with datesRender etc.

    You seem to be having some trouble relating the documentation to your own code, so here is an example of how you should do it. Obviously I haven't tested this, but this should give you the right idea.

    Also, currently you are sending month and year to your server, but fullCalendar will pass you specific start and end dates. You should send these to your server. Then you should modify the server code so that it returns all events within these start and end dates, rather than for a specific months. This is because if, for example, you are using the "week" view instead of the "month" view, the dates that fullCalendar sends will cover 1 week instead of 1 month. So you need a bit more flexibility than just returning a whole month of events.

    jQuery(document).ready(function ($) {
        loadCalendar();  //initialise the calendar
    })
    
    function loadCalendar() {
    
        var calendarEl = document.getElementById('expire_date_events_calendar');
        window.calendarEventsObject = new FullCalendar.Calendar(calendarEl, { // FullCalendar Init
            plugins: ['dayGrid', 'timeGrid'],
            defaultView: 'dayGridMonth',
            views: {
                dayGridMonth: {
                    buttonText: 'Month'
                },
                timeGridWeek: {
                    buttonText: 'Week'
                }
            },
            axisFormat: "H:mm A",
            timeFormat: "H:mm A",
            header: {
                left: 'dayGridMonth,timeGridWeek',
                center: 'title',
                right: 'today prev,next '
            },
            eventRender: function (info) {
                //...
            },
            dayRender: function (dayRenderInfo) {
               //...
            },
            select: function (selectionInfo) {
                //...
            },
            events: function(info, successCallback, failureCallback) {    //get data from db for selected dates
              var dataArray = {
                '_token': '{{ $csrf_token }}',
                'start': info.startStr,
                'end': info.endStr
              }
              var href = "/admin/get_ad_events";
        
              $.ajax({
                  type: "POST",
                  dataType: "json",
                  url: href,
                  data: dataArray,
                  success: function (response) {
                      successCallback(response.events);
                  },
                  error: function (error) {
                      failureCallback(error);
                      popupErrorMessage(error.responseJSON.message);
                  }
              });
            },
            showNonCurrentDates: false,
            displayEventTime: true,
            eventLimit: true, // allow "more" link when too many events
            editable: true,
            allDaySlot: true,
            selectable: true,
            selectHelper: true,
            selectOverlap: false,
            fixedWeekCount: false,
            disableDragging: true,
            aspectRatio: 0.4,
            height: 900,
            eventClick: function (eventClickInfo) {
                //...
                return false;
            }
        });
    }