我需要您的帮助来了解我的 FullCalendar Scheduler v5.5.0 实例的行为。
我的事件源是由来自数据库的基本 SQL 请求生成的 JSON 数组,每个事件都像往常一样具有自己的唯一 ID。
我正在使用一些jQuery代码进行ajax调用以插入/更新/删除事件。
一切正常,但是当我想一个接一个地删除多个事件而不重新加载页面时,则为每个事件多次执行 ajax 删除脚本调用。
例如:我想删除 ID 为 2674 的事件,我单击按钮,它会触发对删除脚本的 ajax 调用(在此步骤中,我可以在 devtool 控制台的网络选项卡中看到对 delete.php 页面的调用,在 post 请求中 ID 为 2674),一切正常, 事件将被删除。
但是当我在紧随其后删除另一个事件(id:2631)时,我有 3 次对删除脚本的调用,第一次和第二次在 post 请求中带有 id 2674(我首先删除的事件),最后一个的 id 为 2631,正如预期的那样。
如果我再次重复此操作,我将有 6 次调用 delete.php 页面:
- 第一个和第二个在 POST 请求中带有 ID 2674(我先删除的事件),
- 第三个ID为2631(我在第二个中删除的事件),
- ID 为 2674 的第 4 个(我首先删除的事件),
- ID 为 2631 的第 5 个(我在第二个中删除的事件), 最后一个 ID 为 2651 的预期。
这是我的代码,你有解释这种行为的想法吗?
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);
}
});
});
});
问题是你正在堆积事件处理程序。每次单击日历上的任何事件时,都会运行eventClick
。在事件单击中,运行$(document).on('click', '#deleteEvent', function() {
,这将添加新的"单击"处理程序以显示删除模式。然后每次显示模式时,它都会运行$(document).on('click', '#delete', function() {
这会向"删除"按钮添加新的"单击"事件处理程序...但是您的代码永远不会删除以前添加到这些按钮的任何事件处理程序。
因此,在您第一次删除某些内容时,它似乎工作正常,但随后如果您再次按 Delete,它将运行与该按钮关联的所有"click"事件处理程序。这就是为什么您可以看到它为您之前删除的事件运行请求 - 它正在重新运行仍附加到按钮的事件处理程序。您可以在 jQuery 中使用 off() 从元素中删除现有的事件处理程序。
例如
$(document).off('click', '#deleteEvent');
$(document).on('click', '#deleteEvent', function() {
//....
$(document).off('click', '#delete');
$(document).on('click', '#delete', function() {