简体   繁体   English

jQuery AJAX 调用在点击处理程序中被多次触发

[英]jQuery AJAX calls getting fired multiple times within click handler

I'm currently developing a PHP web app, and I'm making use of the datatables jQuery plugin, and jQuery AJAX calls to create a dynamic table that can have elements edited, deleted and added. I'm currently developing a PHP web app, and I'm making use of the datatables jQuery plugin, and jQuery AJAX calls to create a dynamic table that can have elements edited, deleted and added. This (seems to be) working fine, however, I've observed that within some of my click handlers, AJAX calls are being fired multiple times - and I'm not quite sure why.这(似乎)工作正常,但是,我观察到在我的一些点击处理程序中,AJAX 调用被多次触发 - 我不太确定为什么。

Here is the page at the moment so you have an idea of where I'm coming from:这是目前的页面,所以你知道我来自哪里:

显示表格的屏幕截图

As you can see, I have basic data on users, and actions to the left.如您所见,我有关于用户的基本数据,以及左侧的操作。 Each row in the table looks like this in the HTML:表中的每一行在 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>

Since (after the initial page load/render) these table rows are being removed/added dynamically, I decided to therefore listen for events at the document level for clicks on the .event-user-delete-staff class, like so:由于(在初始页面加载/渲染之后)这些表行被动态删除/添加,因此我决定在文档级别监听事件以单击.event-user-delete-staff class,如下所示:

$(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');
            }
        });
    });
});

Now, the reason I noticed the AJAX calls are being made multiple times is because I noticed multiple toast messages are being displayed for each delete event (The displaySuccessToast method, all this does is clone a toast template and display it).现在,我注意到 AJAX 调用被多次调用的原因是因为我注意到每个删除事件都会显示多个 toast 消息( displaySuccessToast方法,所有这些都是克隆一个 toast 模板并显示它)。 The following basically happens:基本上会发生以下情况:

  1. First deletion from table - works fine, row is removed and success message displays.第一次从表中删除 - 工作正常,行被删除并显示成功消息。
  2. Second deletion from table - This is where things start to get funky.从表中第二次删除 - 这是事情开始变得时髦的地方。 Correct row is deleted from table, however, two toasts show and two AJAX calls are made.从表中删除了正确的行,但是,显示了两个 toasts 并进行了两个 AJAX 调用。
  3. Third deletion from table - Trend continues, now 3 toasts get displayed and 3 AJAX calls are made.从表中删除第三次 - 趋势继续,现在显示 3 个 toast,并进行了 3 个 AJAX 调用。

Having added some console logs and stepping through the code, I can tell this isn't because the $(document).on('click', '.event-user-delete-staff', function () event listener is firing multiple times. It only fires once per deletion, as it should.添加了一些控制台日志并单步执行代码后,我可以看出这不是因为$(document).on('click', '.event-user-delete-staff', function ()事件侦听器正在触发多个每次删除它只会触发一次,因为它应该。

I think the suspect is the confirmDialog() method, as I've observed via some console logs, it is in here that it is firing multiple times.我认为嫌疑人是confirmDialog()方法,正如我通过一些控制台日志观察到的那样,它在这里多次触发。

This method looks like this:此方法如下所示:

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');
    });
}

However, I suspect it's not really the fault of this method;但是,我怀疑这并不是这种方法的错。 but is some kind of misunderstanding of mine as to how function callbacks like this work, and using variables from the parent scope within them?但是我对 function 这样的回调如何工作以及在其中使用父级 scope 的变量是否存在某种误解?

As I've said;正如我所说; I don't think this is because the event listener itself is firing multiple times, on the second deletion (and beyond...), the event still only logs being called once, it is within the confirmDialog function callback method where it logs twice.我不认为这是因为事件侦听器本身会触发多次,在第二次删除(及以后......)时,事件仍然只记录被调用一次,它在confirmDialog function 回调方法中,它记录了两次.

Can someone please advise what I'm doing wrong here, and what could be causing this behaviour?有人可以告诉我我在这里做错了什么,什么可能导致这种行为?

Edit - For posterity, and anyone else who stumbles across this and wants to know what I changed...编辑- 对于后代,以及其他任何偶然发现这一点并想知道我改变了什么的人......

The problem in this case, is that each time the confirmDialog method was being called, it would add another listener to the yes button.这种情况下的问题是,每次调用confirmDialog方法时,都会向 yes 按钮添加另一个侦听器。 This means, when the yes button in that dialog was clicked, it would fire the most recent event... and all the other ones attached before.这意味着,当单击该对话框中的“是”按钮时,它将触发最近的事件......以及之前附加的所有其他事件。 I simply changed the confirm button yes dialog to look like so:我只是将确认按钮是对话框更改为如下所示:

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

Using off() first ensures no other event listeners are lingering around on that yes button.首先使用off()可确保没有其他事件侦听器在该 yes 按钮上徘徊。 Probably not the best or cleanest solution, but hey, it works.可能不是最好或最干净的解决方案,但嘿,它有效。

A thank you to Nick with his answer below , who pointed out where I was going wrong感谢尼克在下面的回答,他指出了我哪里出错了

You're adding a new event handler to the Yes button in the confirm dialog every time you call confirmDialog :每次调用confirmDialog时,您都会在确认对话框中的Yes按钮中添加一个新的事件处理程序:

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

This means that the first time you click the yes button, yesCallback will get called once, the second time yesCallback will get called twice, etc. etc.这意味着第一次单击 yes 按钮时, yesCallback将被调用一次,第二次yesCallback将被调用两次,依此类推。

You're also doing the same for the No button, but since that just hides the modal it doesn't really affect the operation of the page.您也对No按钮执行相同的操作,但由于这只是隐藏了模式,因此不会真正影响页面的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM