FullCalendar AJAX调用多次触发而不重新加载页面。

3
当我在月视图中点击一天时,会弹出一个模态框。
在该模态框内有一个用于添加新事件的按钮。当我单击该按钮时,将弹出另一个用于添加事件表单的模态框。
问题是,当我频繁打开/关闭第一个模态框并尝试添加事件而不重新加载页面时,即使我仅单击提交一次,AJAX调用也会多次触发。有时它会倍增达7倍。
我不知道问题在哪里。
我的代码如下:
$(document).ready(function() {
      var calendar = $('#calendar').fullCalendar({
        header: {
          left: 'today',
          center: 'prev title next',
          right: 'month,basicWeek,basicDay'
        },
        eventOrder: 'start',
        editable: true,
        droppable: true,
        eventLimit: true,
        selectable: true,
        selectHelper: true,
        events: 'getEvents.php',
        eventRender: function(event, element, view) {
            var today = new Date();
            var startString = moment(event.start).format('YYYY-MM-DD');
            var endString = moment(event.end).format('YYYY-MM-DD');
            $(element).each(function () { 
              $(this).attr('date-num', event.start.format('YYYY-MM-DD')); 
            });
        },
        eventAfterAllRender: function(view){
          for( cDay = view.start.clone(); cDay.isBefore(view.end) ; cDay.add(1, 'day') ){
            var dateNum = cDay.format('YYYY-MM-DD');
            var dayEl = $('.fc-day[data-date="' + dateNum + '"]');
            var eventCount = $('.fc-event[date-num="' + dateNum + '"]').length;
            if(eventCount){
              var html = '<span class="event-count">' + 
                        '<i>' +
                        eventCount + 
                        '</i>' +
                        ' Events' +
                        '</span>';

              dayEl.append(html);
            }
          }
        },
        dayClick: function(start, end, event) {
          var st = start.format('YYYY-MM-DD HH:mm:ss');
          var en = start.format('YYYY-MM-DD HH:mm:ss');

          function fetch_data() {
            $.ajax({
              url: "view-data.php",
              data: 'action=view&start=' + st + '&end=' + en,
              method: "POST",
              success: function(data) {
                $('#view-me').html(data);
                $('#view-data').modal('show');
              }
            });
          }

          fetch_data();

          $(document).on('click', '.add-me', function() {
            $('#start').val(moment($(this).data('start')).format('YYYY-MM-DD[T]HH:mm:ss'));
            $('#end').val(moment($(this).data('end')).format('YYYY-MM-DD[T]HH:mm:ss'));
            $('#ModalAdd').modal('show');

            $('#myFormAdd').on('submit', function(e) { // add event submit
              e.preventDefault();
              doAdd(); // send to form submit function
            });

            function doAdd() { // add event
              var title = $('#title').val();
              var start = $('#start').val();
              var end = $('#end').val();

              $.ajax({
                url: 'addEvent.php',
                data: 'action=add&title=' + title + '&start=' + start + '&end=' + end,
                type: "POST",
                success: function(json) {
                  $('#ModalAdd').modal('hide');
                  fetch_data();
                  calendar.fullCalendar('refetchEvents');
                }
              });
            }
          });
        }
      );

我的PHP代码:view-data.php

 if($_POST['action'] == "view") // view event dayClick
{ 
 $start = $_POST['start'];
 $end = $_POST['end'];
 ?>

  //Add new button
  <button title="add new here" class="add-me" data-start="<?php echo $start; ?>" 
  data-end="<?php echo $end; ?>" rel="dialog" >ADD</button>

<?php 

 $sql = "SELECT * FROM events WHERE start BETWEEN '$start' AND '$end' OR end BETWEEN '$start' AND '$end'";  
 $result = mysqli_query($connect, $sql);  

 if(mysqli_num_rows($result) > 0)  
 {  
  while($row = mysqli_fetch_array($result))  
  {
  ?>

  <span style="overflow:hidden;text-overflow:ellipsis;white-space: nowrap;"><?php echo $row['title']; ?></span>

  <?php
  }
  } else {
     echo "<span>No event</span>";
  }
  }   
  ?>

你的代码不完整,不正确,请创建JS Fiddle以便理解错误。 - Bhumi Shah
@BhumiShah 我已经编辑了我的代码并包含了所有内容。 - Pixcelleen88
你的代码还不正确,你写了 $(document).on('click', '.add-me', function() { with calender? - Bhumi Shah
@BhumiShah 但这就是我的全部代码。是啊,那我该怎么办呢? - Pixcelleen88
2个回答

3

目前在您的dayClick事件处理程序中,您有添加所有其他事件处理程序的代码,并定义了一些函数。这不是一个好的做法,因为这意味着每当用户单击一天时,此代码将运行并继续向页面添加越来越多的事件处理程序。添加事件处理程序不会覆盖先前添加的处理程序,它只会继续添加更多。然后,每次触发添加处理程序的事件时,它会同时执行所有附加到它的事件处理程序。

这就解释了为什么有时你会看到你的ajax调用一遍又一遍地运行-这将是在你已经点击了一天(或不同的天)多次的情况下。

您需要确保您的事件处理代码仅运行一次,并且您的函数仅被声明一次。为此,请将所有该代码移出日历配置。然后,您还需要允许传递一些参数到fetch_data函数中,以便它知道要获取什么,而不依赖于闭包范围:

因此,在您的fullCalendar代码中:

dayClick: function(start, end, event) {
  fetch_data(start, end);
}

这就是在日历配置中所需要的全部内容。
然后,在您的日历配置之外:
function fetch_data(start, end) {
  var st = start.format('YYYY-MM-DD HH:mm:ss');
  var en = start.format('YYYY-MM-DD HH:mm:ss');
  $.ajax({
    url: "view-data.php",
    data: 'action=view&start=' + st + '&end=' + en,
    method: "POST",
    success: function(data) {
      $('#view-me').html(data);
      $('#view-data').modal('show');
    }
  });
}


$(document).on('click', '.add-me', function() {
  $('#start').val(moment($(this).data('start')).format('YYYY-MM-DD[T]HH:mm:ss'));
  $('#end').val(moment($(this).data('end')).format('YYYY-MM-DD[T]HH:mm:ss'));
  $('#ModalAdd').modal('show');
});

$(document).on("submit", '#myFormAdd', function(e) { // add event submit
  e.preventDefault();
  doAdd(); // send to form submit function
});

function doAdd() { // add event
  var title = $('#title').val();
  var start = $('#start').val();
  var end = $('#end').val();

  $.ajax({
    url: 'addEvent.php',
    data: 'action=add&title=' + title + '&start=' + start + '&end=' + end,
    type: "POST",
    success: function(json) {
      $('#ModalAdd').modal('hide');
      //fetch_data(); //it's not clear why you would need to do this here, since you've just hidden the modal which is populates! Pretty sure you don't need it, so I've commented it out
      calendar.fullCalendar('refetchEvents');
    }
  });
}

非常感谢。我快要完成了。我现在唯一的问题是如何在ajax成功添加新事件后,从fetch_data函数中更新模态框$('#view-data').modal('show');内的数据。因为我还在模态框中显示了每天的所有事件。你评论的fetch_data();是我重新获取模态框内数据的方式。所以每当我添加新事件时,事件将自动显示在模态框和日历中。 - Pixcelleen88
这些事件不是已经显示在主日历上了吗?为什么不直接关闭那个模态框呢?如果用户想查看详细信息,他们可以再次点击该日期,但他们已经知道其中的内容,因为他们刚刚在一刻钟前输入了它。可能他们现在想做其他事情。 - ADyson
如果你真的想更新模态框,你可以取消注释那一行并将其更改为fetch_data(moment(start), moment(end));以便再次提供正确的开始和结束日期...假设这些日期没有被用户更改?或者找到另一种方法来使该函数中可用的正确日期可用,例如可能使用数据属性,就像你为添加按钮所做的那样。 - ADyson
1
很棒的解决方案!我也遇到了同样的问题,现在阅读后我理解了问题并且已经解决了!感谢你的回答。 - Jack Maessen

2
$(document).on('click', '.add-me', function(){ 移出 dayClick 回调函数。
每次点击一天,都会为 add-me 添加一个新的点击事件监听器。
因此,点击 3 天将添加 3 个监听器,然后在 add-me 上单击将运行事件处理程序(和 ajax)3 次。

我将 $(document).on('click', '.add-me', function(){ 放在 dayClick 中,这样我可以在 ajax 成功后重新获取模态框。如果我将其移出,如何在 dayClick 中重新获取模态框中的数据?请帮忙。 - Pixcelleen88
1
这没关系。你已经委托给了始终存在的 document - charlietfl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接