首页 > 解决方案 > FullCalendar 奇怪的行为从数据库中删除事件

问题描述

我需要您的帮助来了解我的 FullCalendar Scheduler v5.5.0 实例的行为。

我的事件源是由来自数据库的基本 SQL 请求生成的 JSON 数组,每个事件都像往常一样具有自己的唯一 ID。

我正在使用一些 jQuery 代码来进行 ajax 调用以插入/更新/删除事件。

一切正常,但是当我想在不重新加载页面的情况下一个接一个地删除多个事件时,对每个事件执行多次删除脚本的 ajax 调用。

例如:我想删除 id 为 2674 的事件,我单击为它制作的按钮,它触发了对删除脚本的 ajax 调用(在此步骤中,我可以在网络选项卡中看到对 delete.php 页面的调用发布请求中带有 id 2674 的 devtool 控制台),一切正常,视图上的事件被删除。

但是,当我在 (id: 2631) 之后删除另一个事件时,我对删除脚本有 3 次调用,第一个和第二个在发布请求中使用 id 2674(我首先删除的事件),最后一个使用id 2631 符合预期。

如果我再次重复此操作,我将对 delete.php 页面进行 6 次调用:

这是我的代码,你有什么想法来解释这种行为吗?

document.addEventListener('DOMContentLoaded', function() {
  var initialLocaleCode = 'fr';
  var url ='./';
  var calendarEl = document.getElementById('calendar');

  var calendar = new FullCalendar.Calendar(calendarEl, {
    locale: 'fr',
    firstDay: 1,
    hiddenDays: [0], // hide Tuesdays and Thursdays
    selectable: true,
    slotDuration: '00:20:00',
    slotMinTime: '08:00:00',
    slotMaxTime: '20:00:00',
    allDaySlot: false,
    headerToolbar: {
      left: 'prev next today',
      center: 'title',
      //right: 'resourceTimeGridDay,dayGridMonth,timeGridDay,listDay,listWeek'
      right: 'resourceTimeGridDay,resourceTimeGridSixDay,dayGridMonth'
    },
    titleFormat: { // will produce something like "Tuesday, September 18, 2018"
      month: 'long',
      year: 'numeric',
      day: 'numeric',
      weekday: 'long'
    },
    views: {
      listDay: { buttonText: 'list day' },
      listWeek: { buttonText: 'list week' },
      dayGridMonth: { buttonText: 'Mois' },
      timeGridDay: { buttonText: 'Jour' },
      resourceTimeGridDay: { buttonText: 'Jour'},
      resourceTimeGridSixDay: {
        type: 'resourceTimeGrid',
        duration: { days: 6 },
        buttonText: 'Semaine',

      }
    },
    datesAboveResources:true,
    nowIndicator: true,
    contentHeight: 900,
    initialView: 'resourceTimeGridDay',
    initialDate: curdate,
    navLinks: true, // can click day/week names to navigate views
    editable: true,
    dayMaxEvents: true, // allow "more" link when too many events
    resources: [
      {
        title: 'Frédéric Xavier',
        id: 'fred'
      }, {
        title: 'Emmanuelle Chouin',
        id: 'manu'
      }
    ],
    eventDidMount: function(info) {
      var start = info.event.start;
      var end = info.event.end;
      var startTime;
      var endTime;
      if (!start) {
        startTime = '';
      } else {
        startTime = start;
        startevent = start.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
      }

      if (!end) {
        endDate = '';
        endevent ='';
      } else {
        endTime = end;
        endevent = end.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
      }
      var title = startevent + " - " + endevent + " " + info.event.title;
      var description = info.event.extendedProps.description;
      if (!info.event.extendedProps.description) {
        description = '';
      }
      $(info.el).popover({
        title: title,
        placement:'top',
        trigger : 'hover',
        content: description,
        container:'body'
      });

      $('.popover.in').remove(); //<--- Remove the popover 
      //$(info.el).popover('show');
      if(info.event.extendedProps.description){          
        $(info.el).find(".fc-event-title").append(" <i class='fas fa-exclamation-triangle fa-lg red-text'></i>");
      }
    },
    dateClick: function(info) {
      $('#event').modal('show');
      var str = info.dateStr
      $('#datedeb').val(str.substring(0,10)).focusin();
      $('#heuredeb').val(str.substring(11,  str.indexOf(':00+'))).focusin();
      $("input[name='resource'][value='" + info.resource.id + "']").prop('checked', true);
      var twentyMinutesLater = new Date(str);
      twentyMinutesLater.setTime(twentyMinutesLater.getTime() + 20*60000);
      var test = twentyMinutesLater + ' ';
      $('#heurefin').val(removeN(test, 16).substring(0,5)).focusin();
    },
    select: function(info) {
      var str = info.startStr
      var str2 = info.endStr
      $('#event').modal('show');
      $('#datedeb').val(str.substring(0,10)).focusin();
      $('#heuredeb').val(str.substring(11,  str.indexOf(':00+'))).focusin();
      $("input[name='resource'][value='" + info.resource.id + "']").prop('checked', true);
      $('#heurefin').val(str2.substring(11,  str2.indexOf(':00+'))).focusin();
    },
    events: url+'api/load.php',
    eventDrop: function(arg) {
      var madate = arg.event.startStr;
      var datedeb = madate.substring(0,10);
      var heuredeb = madate.substring(11,madate.indexOf(':00+'))
      var end = arg.event.endStr;
      var heurefin = end.substring(11,end.indexOf(':00+'))
      $.ajax({
        url:url+"/api/update.php",
        type:"POST",
        data:{id:arg.event.id, date:datedeb, start:heuredeb, end:heurefin, title:arg.event.title,color:arg.event.backgroundColor, commentaire:arg.event.extendedProps.description, resource:arg.event._def.resourceIds[0]},
      });
      
      calendar.refetchEvents();
    },
    eventDragStop: function(arg) {
      $('.popover').remove(); //<--- Remove the popover 
      calendar.refetchEvents();
      $('.popover').remove(); //<--- Remove the popover 
    },
    eventResize: function(arg) {
      var madate = arg.event.startStr;
      var datedeb = madate.substring(0,10);
      var heuredeb = madate.substring(11,madate.indexOf(':00+'))
      var end = arg.event.endStr;
      var heurefin = end.substring(11,end.indexOf(':00+'))

      $.ajax({
        url:url+"api/update.php",
        type:"POST",
        data:{id:arg.event.id, date:datedeb, start:heuredeb, end:heurefin, title:arg.event.title,color:arg.event.backgroundColor, commentaire:arg.event.extendedProps.description, resource:arg.event._def.resourceIds[0]},
      });
      calendar.refetchEvents();
      //location.reload();
    },
    eventClick: function(arg) {
      var id = arg.event.id;
      $('#editEventId').val(id);
      $('#deleteEvent').attr('data-id', id); 
      //$('#modif').modal('show');

      $.ajax({
        url:url+"api/getevent.php",
        type:"POST",
        dataType: 'json',
        data:{id:id},
        success: function(data) {
          $('#edit-nom').val(data[0].title).focusin();
          $('#edit-commentaire').val(data[0].description).focusin();
          $('#edit-datedeb').val(data[0].start.substring(0,10)).focusin();
          //alert(data[0].start.substring(11,data[0].start.indexOf(':00')));
          $('#edit-heuredeb').val(data[0].start.substring(11,data[0].start.length+5)).focusin();
          $('#edit-heurefin').val(data[0].end.substring(11,data[0].end.length+5)).focusin();
          $("input[name='editcolor'][value='" + data[0].backgroundColor + "']").prop('checked', true);
          $("input[name='edit-resource'][value='" + data[0].resourceId + "']").prop('checked', true);
          $('.Nom').replaceWith('<span class="Nom font-weight-bold text-danger">'+data[0].title+'</span>');
                
          $('#modif').modal('show');
        }
      });

      $(document).on('click', '#deleteEvent', function() {
        $('#modif').modal('hide');
        $('#modalConfirmDelete').modal('show');
        $('#delete').replaceWith('<button type="button" class="btn  btn-outline-danger" id="delete" data-id="'+id+'">Oui</button>');

        $(document).on('click', '#delete', function() {
          $.ajax({
            url:url+"api/delete.php",
            type:"POST",
            cache : false,
            data:{id:id},
            success: function(msg) { 
              console.log(msg);
              $('#modalConfirmDelete').modal('hide');
              calendar.refetchEvents(); 
            },
          });
        });
      });
    }
  });

  calendar.render();

  $(document).on('click', '#createEvent', function(event) {
    var request_method = $("#form").attr("method");
    var post_url = $( "#form").attr('action');
    var post_data = $( "#form" ).serialize();

    $.ajax({
      type: request_method,
      url: post_url,
      data: post_data,
      success: function(msg) { 
        $("#form")[0].reset();
        $('#event').modal('hide');
        console.log(msg);
        calendar.refetchEvents();
      },
      error: function(msg) {
        console.log(msg);
      }
    });
  });

  $(document).on('click', '#editEvent', function(event) {
    var request_method = $("#formupdate").attr("method");
    var post_url = $( "#formupdate").attr('action');
    var post_data = $( "#formupdate" ).serialize();

    $.ajax({
      type: request_method,
      url: post_url,
      data: post_data,
      success: function(msg) { 
        console.log(msg);
        $("#formupdate")[0].reset();
        $('#modif').modal('hide');
        calendar.refetchEvents();
      },
      error: function(msg) {
        console.log(msg);
      }
    });
  });
});

标签: javascriptjqueryfullcalendarfullcalendar-schedulerfullcalendar-5

解决方案


问题是您正在堆积事件处理程序。每次您单击日历上的任何事件时,eventClick都会运行。在事件点击中,您运行$(document).on('click', '#deleteEvent', function() {它会添加一个新的“点击”处理程序以显示删除模式。然后每次显示模式时,它都会运行$(document).on('click', '#delete', function() {,向删除按钮添加一个新的“单击”事件处理程序......但是您的代码永远不会删除以前添加到这些按钮的任何事件处理程序。

因此,它在您第一次删除某些内容时似乎工作正常,但随后如果您再次按 Delete,它将运行与该按钮关联的所有“单击”事件处理程序。这就是为什么您可以看到它正在运行对您之前删除的事件的请求 - 它正在重新运行仍附加到按钮的事件处理程序。您可以在 jQuery 中使用off()从元素中删除现有的事件处理程序。

例如

$(document).off('click', '#deleteEvent');
$(document).on('click', '#deleteEvent', function() {

//....

  $(document).off('click', '#delete');
  $(document).on('click', '#delete', function() {

推荐阅读