как обновить fullcalendar v4 после изменения объекта событий с помощью ajax

Я использую fullcalendar v4 для отображения событий. события обычно отображаются при загрузке, но мне нужно добавить фильтр, используя несколько флажков, и обновить события полного календаря после флажка onchange с помощью ajax.

после изменения я получаю новые события объекта, но мне нужно обновить полный календарь, я пытаюсь использовать calendar.render();, но не работает

fullcalendar V4 !!

скрипт fullcalendar

 var taskEvents = JSON.parse($("input[name=tasks_events]").val());
        var calendarEl = document.getElementById('tasks_calendar');
        var  calendar = new FullCalendar.Calendar(calendarEl, {
            locale: 'fr',
            plugins: [ 'interaction', 'dayGrid', 'timeGrid' ],
            header: {
                left: 'prev,next today',
                center: 'title',
                right: 'dayGridMonth,timeGridWeek'
            },
            defaultDate: new Date(),
            defaultView: 'timeGridWeek',
            minTime: "09:00:00",
            maxTime: "20:00:00",
            weekends:false,
            businessHours: true, // display business hours
            editable: true,
            selectable: true,
            droppable: true,
            //events:taskEvents ,
            select: function(info) {
                $('#newTaskFormLabel').html('Commence à '+"<b> " + moment(info.startStr).format('DD-MM-YYYY HH:mm') + "</b> "+" fin à " +"<b> " + moment(info.endStr).format('DD-MM-YYYY HH:m:m')) +"</b>"
                $('#newTaskForm').modal('show');
                $('#newTaskForm input[name=start_at]').val(info.startStr);
                $('#newTaskForm input[name=end_at]').val(info.endStr);
            },
            eventClick: function(info) {
                $('#editTaskForm').modal('show');
                console.log(info);
                editTask(info.event);
            },
            // dateClick: function(info) {
            //     alert('clicked ' + info.dateStr);
            // },
            eventResize: function(info) {    
                $('.popover.in').remove();     
                if (confirm("Êtes-vous sûr de vouloir appliquer ces modifications?")) {
                    submitTimeChanges(info.event);
                }else{
                    info.revert();
                }
            },   
            eventDrop : function(info){
                $('.popover.in').remove(); 
                // $(info.el).removeAttr('aria-describedby');
                if (confirm("Êtes-vous sûr de vouloir appliquer ces modifications?")) {
                    submitTimeChanges(info.event);
                }else{
                    info.revert();
                }
            },
            eventRender: function(info) {

                $(info.el).append('<img src="'+document.location.origin+'/'+info.event.extendedProps.user_avatar+'" class="img-circle event-avatar" alt="User Image">');
                let state = function (state) { 
                    if(state =="not_started") return "Pas encore commencé";
                    if(state =="started") return "Commencé";
                    if(state =="finish") return "Terminer";
                }
                $(info.el).popover({
                    title: info.event.title,
                    content: function () {
                        let html ="<p>"+moment(info.event.start).format('DD-MM-YYYY HH:mm')+' / '+moment(info.event.end).format('DD-MM-YYYY HH:mm')+"</P>"
                        +"<p>"+info.event.extendedProps.description+"</p>"
                        +"<p>"+"Utilisateur : "+info.event.extendedProps.user+"</p>"
                        +"<p>"+"Projet : "+info.event.extendedProps.project+"</p>"
                        +"<p>"+"Fonction : "+info.event.extendedProps.activity+"</p>"
                        +"<a class='btn btn-primary btn-xs'>"+state(info.event.extendedProps.state)+"</a>";
                        return html;
                    },
                    trigger: 'hover',
                    placement: 'top',
                    html: 'true',
                    container: 'body'
                    });
            },

        });
        calendar.addEventSource( taskEvents );
        calendar.render();
//--------------------------------------------------------

скрипт ajax

var getTasks = function (data){
            $.ajax({
                url:"/admin/get-users-tasks",
                type:"POST",
                data :{
                    users:data,
                },
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                },
                success: function (response) {
                    calendar.addEventSource( response );
                    calendar.refetchEvents();
                },
                error: function(response) {
                    new PNotify({
                        title: "Opération échoué",
                        text: response.message,
                        type: "error"
                      });
                }
              });
        }

при изменении функции флажка

 function onChangeUserCheckbox() {  
        $("input[name*=selected_user]").on('change',function () {
            var selectedUsers = [];
            $.each($("input[name*='selected_user']:checked"), function(){            
                selectedUsers.push($(this).val());
            });
            getTasks(selectedUsers);
            // getTasks(JSON.stringify(selectedUsers));
        })
    }

person Boutamente abdessamad    schedule 30.04.2019    source источник


Ответы (4)


Вы не объяснили, что именно не так с вашим кодом, но я вижу, что когда вы получаете ответ от вызова AJAX, вы каждый раз добавляете новый источник событий. Я также вижу, что вы никогда не удаляете какой-либо предыдущий источник событий, поэтому вы будете получать все больше и больше событий. Я предполагаю, что это проблема, о которой вы спрашиваете.

Но вместо того, чтобы постоянно добавлять / удалять источники событий, было бы проще объявить это как единый источник событий, который можно обновлять и обновлять. Чтобы заявить об этом источнике.

Вот немного исправленного кода, который будет иметь немного больше смысла:

var calendarEl = document.getElementById('tasks_calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
  eventSources: [
    JSON.parse($("input[name=tasks_events]").val()), //static event source
    getTasks //pass a reference to a function, so we have a dynamic, updateable event source
  ]
  ///....all your other options go here as well....
});

$("input[name*=selected_user]").on('change',function () {
  calendar.refetchEvents(); //this will automatically cause the "getTasks" function to run, because it's associated with an event source in the calendar
});

var getTasks = function(fetchInfo, successCallback, failureCallback) { //the input parameters are the ones shown in the fullCalendar documentation
  //find the currently selected users
  var selectedUsers = [];
  $.each($("input[name*='selected_user']:checked"), function(){            
    selectedUsers.push($(this).val());
  });

  //run the ajax call
  $.ajax({
    url: "/admin/get-users-tasks",
    type: "POST",
    data: {
      users: selectedUsers,
    },
    headers: {
      'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    },
    success: function (response) {
      successCallback(response); //pass the event data to fullCalendar via the provided callback function
    },
    error: function(response) {
      new PNotify({
        title: "Opération échoué",
        text: response.message,
        type: "error"
      });

      failureCallback(response); //inform fullCalendar of the error via the provided callback function
    }
  });
}

Некоторые примечания:

1) В этой версии при загрузке календаря он немедленно отправляет запрос AJAX на сервер и пытается получить события. Однако, поскольку флажки не установлены, данные на сервер не передаются. Я не знаю, что в данный момент делает ваш серверный код в этой ситуации или что вы от него хотите. Я думаю, он должен либо вернуть все возможные события, либо вообще не вернуть. В любом случае вам нужно убедиться, что код сервера настроен для обработки этой ситуации и возврата тех данных, которые имеют смысл.

2) Я также добавил сюда другой набор событий (взятых из скрытого поля) в качестве источника событий. Нет необходимости добавлять его отдельно через addEventSource, так как вы добавляете его сразу после загрузки календаря - вместо этого вы можете просто объявить его в параметрах.

3) Я не использовал здесь предоставленные fetchInfo данные, но в идеале вы должны брать значения даты начала и окончания из этого объекта и отправлять их на свой сервер в качестве параметров, и ваш сервер должен использовать их для фильтрации данных и только возвращать события, даты начала которых попадают между этими двумя датами. Это будет более эффективно, потому что тогда вы будете возвращать только данные, которые фактически будут отображаться в календаре, а не все задачи, которые когда-либо выполнялись пользователем - если вы думаете об этом, когда ваше приложение использовалось для Через несколько месяцев у них начнется много прошлых данных, которые нет смысла загружать каждый раз, так как они почти наверняка не будут просматриваться. (Обратите внимание, что если пользователь переходит к прошлым / будущим датам, а fullCalendar не имеет данных о событиях для этих дат, он снова запустит вызов AJAX и попросит сервер предоставить его. Но если пользователь никогда не просматривает эти даты, это не будет беспокоить, и вы сэкономите часть полосы пропускания и время обработки.)

Документацию по настройке источников событий в параметрах календаря см. https://fullcalendar.io/docs/eventSources. .

person ADyson    schedule 02.05.2019
comment
Спасибо за подробный ответ. Я исправляю ошибку, используя метод get вместо публикации в запросе ajax. Я не знаю, хорошая ли это практика, но все работает нормально, смотрите выше - person Boutamente abdessamad; 04.05.2019
comment
Выше где? Я не вижу ответа, который вы написали. В любом случае, если это все, что вы изменили, вы все равно столкнетесь со всеми другими проблемами, которые я описал позже. - person ADyson; 04.05.2019

Что я делаю: уничтожаю календарь и заново его визуализирую

  1. не загружайте календарь, как указано в документе, но:
function LoadCalendar() {
        if (typeof calendar != "undefined") {
            document.getElementById("calendar").innerHTML = "";
        }
        var calendarEl = document.getElementById('calendar');
        calendar = new FullCalendar.Calendar(calendarEl, {
        //... parameters
        });
        calendar.render();
    }
  1. Затем при загрузке:
function FirstCalendar() {
        MesEvents = "$events"; // Ajax script is executed and give $events
        LoadCalendar();
    }
        document.addEventListener('DOMContentLoaded', FirstCalendar);
  1. И, наконец, для обновления Ajax:
function makeRequest(event) {
        //... ajax instructions
        httpRequest.onreadystatechange = function() { changeContents(httpRequest); };
        httpRequest.open('POST', 'url/ajax.php', true);
        httpRequest.send(oData);
    }
    function changeContents(httpRequest) {
        try {
            if (httpRequest.readyState == XMLHttpRequest.DONE) {
                if (httpRequest.status == 200) {
                    reponse = JSON.parse(httpRequest.responseText);
                    MesEvents = JSON.parse(reponse.Events);
                    LoadCalendar();
                } else {
                    alert('Un problème est survenu avec la requête : ' + httpRequest.status);
                }
            }
        }
        catch( e ) {
            alert(\"Une exception s’est produite (changeContents) : \" + e.description);
        }
    }
person Jeremy    schedule 28.05.2019

Полный календарь v4

Во-первых, я хотел бы поблагодарить ADyson и Boutamente за ответы. это помогло мне найти решение. Мой код выглядит следующим образом:

<script>

  document.addEventListener('DOMContentLoaded', function() {

    var calendarEl = document.getElementById('calendar');
    var calendar = new FullCalendar.Calendar(calendarEl, {

    plugins: [ 'dayGrid','interaction','googleCalendar' ],
    editable: true,
    selectable: true,

    dateClick: function(info) {

      // open a modal form and submit using ajax

    },

    // eventClick is not required if you are using eventRender with bootstrap tooltip or popover. However it is up to you.

    // eventClick: function(info) {

    //   alert('Event: '+titleCase(info.event.title)+'\n'+'Start: '+info.event.start.toDateString()+' '+info.event.start.toLocaleTimeString()+'\n'+'End: '+info.event.end.toDateString()+' '+info.event.end.toLocaleTimeString());

    // },

    // there is no need to set a static event source if you are
    // fetching events using custom function
    // eventSources allow you to fetch events using fn,json,array

    eventSources: [
      {
        // FullCalendar will call this function whenever it needs new data
        // fetchInfo is auto populated with start and end dates of calendar
        // I manipulate the start and end data in my controller to search the db
        // for more info on fetchInfo Object, https://fullcalendar.io/docs/events-function
        // base_url() is a custom function

        events:function(fetchInfo, successCallback, failureCallback) {

          $.ajax({
            type:'GET',
            url: base_url() + "/fetchInfo",
            data:{"start":fetchInfo.start.toDateString(),"end":fetchInfo.end.toDateString()},
            success: function(response) {

              successCallback(response.dates.map(function(event) {

                return {
                  id:event.id,
                  title:event.title,
                  start:event.start,
                  end:event.end,
                }

              })
              );
            },
            error: function(response){
              console.log(response);
              failureCallback(response);
            },
          }); 
        },
        color: 'yellow',
      }
    ],

    eventDrop: function(info) {

        if(!confirm("Are you sure about this change?")) {
          info.revert();
        }
        // call function to update event date with ajax
        modifyEvent(info.event);

    },

    eventRender: function(info) {

      $(info.el).popover(
        {
          title:titleCase(info.event.title),
          content:multiline('Start: ' + info.event.start.toDateString() + ' ' + info.event.start.toLocaleTimeString() + '\n' + 'End: ' + info.event.end.toDateString() + ' ' + info.event.end.toLocaleTimeString()),
          html:true,
          trigger:'hover',
          container:'body',
          placement:'top',
        });
    },

  });

  // refetch events once you close the modal form

  $('#createEventModal').on('hidden.bs.modal', function() {

      calendar.refetchEvents();

  });

  calendar.render();

  });


</script>
person Bruce Tong    schedule 17.07.2019

Пожалуйста, проверьте код ниже:

 $.ajax({
        url:"/admin/get-users-tasks/"+data,
        type:"GET",
        success: function (response) {
            calendar.addEventSource( '/admin/get-users-tasks/'+data );
            var eventSource = calendar.getEventSources();
            eventSource[0].remove();
            eventSource[0].refetch();
        },
        error: function(response) {
            new PNotify({
                title: "Opération échoué",
                text: response.message,
                type: "error"
              });
        }
      });
person Jaimin Rlogical    schedule 01.05.2019
comment
вы не объяснили свой ответ, что затрудняет понимание. Что вы изменили, и почему это решит проблему, указанную в вопросе? Также вы использовали синтаксис fullCalendar v3 вместо v4, что не сработает. Предлагаю вам ознакомиться с последней документацией - person ADyson; 02.05.2019
comment
когда я использую сообщение метода, я передаю ответ в calendar.addEventSource (response); но я получаю ошибку в консоли, он берет ответ json и добавляет его в качестве параметра в URL-адрес, потому что я использую get - person Boutamente abdessamad; 04.05.2019