【问题标题】:jQuery AJAX calls getting fired multiple times within click handlerjQuery AJAX 调用在点击处理程序中被多次触发
【发布时间】:2020-12-18 01:48:28
【问题描述】:

我目前正在开发一个 PHP Web 应用程序,我正在使用 datatables jQuery 插件和 jQuery AJAX 调用来创建一个可以编辑、删除和添加元素的动态表。这(似乎)工作正常,但是,我观察到在我的一些点击处理程序中,AJAX 调用被多次触发 - 我不太确定为什么。

这是目前的页面,所以你知道我来自哪里:

如您所见,我有关于用户的基本数据,以及左侧的操作。表格中的每一行在 HTML 中如下所示:

<tr>
    <td><?= $userAccount['firstName'] ?></td>
    <td><?= $userAccount['lastName'] ?></td>
    <td><?= $userAccount['email'] ?></td>
    <td><?= $userAccount['jobTitle'] ?></td>
    <td class="text-right enrolr-datatable-actions-min-width">
        <i data-userId="<?= $userAccount['id'] ?>" class="fas fa-user-edit enrolr-standard-icon mr-2 event-user-edit"></i>
        <i data-userId="<?= $userAccount['id'] ?>" class="fas fa-user-times enrolr-danger-icon mr-2 event-user-delete-staff"></i>
    </td>
</tr>

由于(在初始页面加载/渲染之后)这些表行正在被动态删除/添加,因此我决定在文档级别监听事件以获取对 .event-user-delete-staff 类的点击,如下所示:

$(document).on('click', '.event-user-delete-staff', function () {
    // Storing some details for later use by handlers
    const userEmail = $(this).closest('tr').find('td').eq(2).html();
    const $button = $(this);

    // Shows confirm dialog, only performs deletion when "yes" is clicked, which causes the third function parameter to run
    confirmDialog(`Are you sure you want to delete ${userEmail}? This action cannot be undone.`, 'Confirm Deletion', function () {
        const $parentToRemove = $button.closest('tr');

        // Make post to remove user.
        $.ajax({
            type: 'POST',
            url: '../php/account/_deleteUser.php',
            data: {
                id: $button.attr('data-userId')
            },
            dataType: 'json',
            success: function (response) {
                // Handle response.
                if (response.success == true) {
                    displaySuccessToast(response.message);
                    // Fade out row then update datatable.
                    $parentToRemove.fadeOut(500, () => {
                        staffTable.row($parentToRemove).remove().draw();
                    });
                } else {
                    displayErrorToastStandard(response.message);
                }
            },
            error: function () {
                // Show error on failure.
                displayErrorToastStandard('Something went wrong while handling this request');
            }
        });
    });
});

现在,我注意到 AJAX 调用被多次调用的原因是因为我注意到每个删除事件都会显示多个 toast 消息(displaySuccessToast 方法,所有这些都是克隆一个 toast 模板并显示它) .基本上会发生以下情况:

  1. 第一次从表中删除 - 工作正常,行被删除并显示成功消息。
  2. 从表中第二次删除 - 这是事情开始变得时髦的地方。从表中删除了正确的行,但是显示了两个 toasts 并进行了两个 AJAX 调用。
  3. 第三次从表中删除 - 趋势仍在继续,现在显示 3 个 toast 并进行了 3 个 AJAX 调用。

添加了一些控制台日志并单步执行代码后,我可以看出这不是因为$(document).on('click', '.event-user-delete-staff', function () 事件侦听器多次触发。每次删除它只会触发一次,这是应该的。

我认为嫌疑人是 confirmDialog() 方法,正如我通过一些控制台日志观察到的那样,它在这里多次触发。

这个方法看起来像这样:

window.confirmDialog = function (message, title, yesCallback) {
    // Sets some details in the confirm dialog
    $('#confirmMessage').html(message);
    $('#confirmTitle').html(title);

    // Shows the modal
    $('#confirmModal').modal('show');

    // On the "yes" button within the dialog being clicked, hides modal and calls the yesCallback function.
    $('#confirmBtnYes').on('click', function () {
        $('#confirmModal').modal('hide');
        yesCallback();
    });

    // On "no" just hides the modal.
    $('#confirmBtnNo').on('click', function () {
        $('#confirmModal').modal('hide');
    });
}

但是,我怀疑这并不是这种方法的错;但是我对像这样的函数回调如何工作以及在其中使用父作用域中的变量是否存在某种误解?

正如我所说的;我不认为这是因为事件侦听器本身会触发多次,在第二次删除时(以及以后......),事件仍然只记录被调用一次,它在 confirmDialog 函数回调方法中记录两次。

有人能告诉我我在这里做错了什么吗?是什么导致了这种行为?

编辑 - 给后代,以及任何偶然发现这个并想知道我改变了什么的人......

在这种情况下的问题是,每次调用confirmDialog 方法时,它都会向“是”按钮添加另一个侦听器。这意味着,当单击该对话框中的“是”按钮时,它将触发最近的事件......以及之前附加的所有其他事件。我只是将确认按钮是对话框更改为如下所示:

$('#confirmBtnYes').off().on('click', function () {
    $('#confirmModal').modal('hide');
    yesCallback();
});

首先使用off() 确保没有其他事件侦听器在那个yes 按钮上徘徊。可能不是最好或最干净的解决方案,但嘿,它有效。

感谢Nick with his answer below,谁指出我哪里出错了????

【问题讨论】:

  • 这是旧版本的 jQuery 吗?升级并使用 .one() 可能会解决问题。如果您发布生成的 HTML,它会有所帮助。阅读此stackoverflow.com/questions/26925611/… 和此stackoverflow.com/questions/26475445/…
  • 您好,感谢您提供的快速 cmets,我已经查看了事件侦听器选项卡 - 据我所知,每次都没有创建任何新的事件侦听器。我可以通过控制台日志验证这一点,因为它只在事件处理程序的直接范围内记录一次。这不是旧版本的 jQuery,我会尝试使用 one() 方法,如果有帮助的话。
  • @JakeH 我正要发布与 Nick 提供的答案类似的内容,但是我建议您使用另一个 Ajax 调用加载表数据,因为您可能会在某个地方到达堆栈点

标签: javascript php html jquery ajax


【解决方案1】:

每次调用confirmDialog 时,您都会在确认对话框中的Yes 按钮中添加一个新的事件处理程序:

$('#confirmBtnYes').on('click', function () {
    $('#confirmModal').modal('hide');
    yesCallback();
});

这意味着当您第一次单击“是”按钮时,yesCallback 将被调用一次,第二次 yesCallback 将被调用两次,依此类推。

你也对No按钮做同样的事情,但是因为它只是隐藏了模式,它并没有真正影响页面的操作。

【讨论】:

  • 该死的,这是一个面对面的时刻。我怎么能这样做,这样我就不会最终将多个事件侦听器添加到“是”按钮?只需使用one 而不是on
  • 只需将这些事件处理程序分配添加到创建确认对话框模式的代码中(或 $(document).ready 代码,如果它在页面的 HTML 中)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多