简体   繁体   中英

JavaScript event in function triggered multiple times

I am having a hard time understanding some aspects of JavaScript functions and event handlers.

In the application I'm working on, the user owns a collection of books. Each time he connects, a list of his books is displayed and he has a button to delete a book if he wants to. First, I wrote the following function:

    function deleteBook(book_to_delete) {
        console.log('Called');
        // Other actions to perform to delete the book
    }

    $(document).on('click', '#user-books-list button.delete', function () {
        var self = $(this);
        var book_to_delete = self.attr('id').replace('delete-', '');
        console.log('Book to delete: ' + book_to_delete);

        // If the user wants to delete a book :
        // Then display a warning on a modal
        $('#confirm-book-deletion').removeClass('hidden');

        // If the user clicks 'no' then hide the warning and do nothing else
        $('#book-deletion-no').on('click', function () {
            // Hiding the modal
            $('#confirm-book-deletion').addClass('hidden');
        });

        // It the user clicks yes, then delete the book
        $('#book-deletion-yes').on('click', function () {

            // Display the book's id and call deletebook()
            console.log('Trigger for ' + book_to_delete);
            deleteBook(book_to_delete);

            // Hiding the modal
            $('#confirm-book-deletion').addClass('hidden');
        });

        // Make sure we exit this function
        return;

    });

The problem is that my trigger $('#book-deletion-yes') get fired multiple times. If I do the following:

  • Book 1 --> Delete --> Cancel (triggers $('#book-deletion-no'), nothing happens)
  • Book 2 --> Delete --> Cancel
  • Book 3 --> Delete --> Confirm

Then instead of only deleting book 3, it deletes books 1, 2, and 3. The "Book 3" step returns the following:

Book to delete: 3
Trigger for 1
Called
Trigger for 2
Called
Trigger for 3
Called

I changed my code to the following, moving $('#book-deletion-no') and $('#book-deletion-yes') out of the main function, and now it works:

    function deleteBook(book_to_delete) {
        // Make sure there is indeed a book to delete
        if (book_to_delete !== undefined) {
            console.log('Called');
            // Other actions to perform to delete the book
        } else {
            console.error('Book id undefined');
        }
    }

    var book_to_delete = undefined;
    $(document).on('click', '#user-books-list button.delete', function () {
        var self = $(this);
        book_to_delete = self.attr('id').replace('delete-', '');

        // Then display a warning
        $('#confirm-book-deletion').removeClass('hidden');
    });

    // If the user clicks 'no' then hide the warning and do nothing else
    $('#book-deletion-no').on('click', function () {
        $('#confirm-book-deletion').addClass('hidden');
        // Reset book_to_delete value
        book_to_delete = undefined;
    });

    // It the user clicks yes, then delete the book
    $('#book-deletion-yes').on('click', function () {
        $('#confirm-book-deletion').addClass('hidden');
        // Delete the book
        console.log('Trigger for ' + book_to_delete);
        deleteBook(book_to_delete);
    });

Can someone help me understand why my first attempt did not work, and the main differences between the two? I really don't get why the first code does this weird "loop" through all the former book_to_delete values as this is not even an array.

Thanks

I am reposting here @Teemu's answer to close this topic.

In the first snippet you're adding new click listeners every time the document is clicked. jQuery on is based on the native addEventListener, which is capable to attach multiple listeners of the same type to the elements, the newly-attached event doesn't override the existing events.

My problem was that I didn't understand how jQuery on worked and was attaching one event on each click, for each book, even if I chose to "cancel" the deletion. Once I finally chose to delete a book, it triggered all of the events... and thus deleted all the books I already clicked on at least once.

jQuery on reference: https://api.jquery.com/on/

The.on() method attaches event handlers to the currently selected set of elements in the jQuery object.

This method keeps attaching events to the clicked element. It does not replace the event on each click. To detach an event, use the off method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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