简体   繁体   中英

Trying to change jQuery click handler of parent fires off new click event

I'm experiencing some (to me) unexpected behavior from event listeners using jQuery, but I expect it's just the underlying Javascript functionality that's confusing me. I think there's a good chance that the answer to my problem is fairly simple, but I can't figure it out.

I have a <div> with a status in it, which is 'New' by default. I want to be able to click on that <div> and bring up a pair of buttons, one which allow you to replace the 'New' status text with 'Complete', and another which will cancel the action, removing the buttons and displaying the 'New' status text again.

I can get everything to work, and it all works fine if I use a different element to display the buttons, but when I try to temporarily replace the text in the <div> , something strange happens.

When I try to reset the original click event for the <div> , what appears to happen is that the click on the cancel button also triggers the just-set click event as well. This re-displays the buttons, so it looks like the cancel button just didn't work. (I was stuck on that for a while...)

I've made a very simple JSFiddle that shows the problem I'm having:

https://jsfiddle.net/pn1q658w/4/

And there's also a slightly modified version that shows things working as long as I've got the cancel button in a different element than the element where I'm resetting the original click function:

https://jsfiddle.net/pn1q658w/3/

I assume this has something to do with the fact that I don't completely understand the way that the timing of these events works. The same click appears to be firing off an event that is set during an action taken because of that click, which I didn't expect, but may very well be how things are supposed to work.

My question is how can I have a click event which is trying to set a click listener on a parent element not fire off the new click at the same time?

Or, if I've completely misunderstood the nature of my mistake, an indication of what I have done wrong would be much appreciated. Thank you!

UPDATED

Just like @charlietfl said, I bleive that the simplest way is to separe the elements everyone with his own class, See WORKED FIDDLE HERE :

HTML :

<div id="elementId">
    <span class='text'>New</span>
</div>

JS :

$(function(){

    var newBtn = '<button class="btn btn-default complete">Complete?</button><button class="btn btn-default cancel">X</button>';

    //Handle the click in the text span         
    $("#elementId").on("click","span.text",function(e){
        $(this).html(newBtn);    
    });

    //Handle the click in the complete button         
    $("#elementId").on("click","button.complete",function(e){
        $('#elementId').html("<span class='text'>Completed</span>");
    });

    //Handle the click in the cancel button 
    $("#elementId").on("click","button.cancel",function(e){
        $('#elementId').html("<span class='text'>New</span>");
    });

});

I hope that this code help you.

Need to understand that when you click on an element inside another element...you are still clicking on the parent as well.

Events "bubble" or "propagate" up the DOM tree all the way to the document...unless told to stopPropagation()

What you are seeing is expected behavior.

You can prevent that bubbling by:

$(selector).click(function(event){

   event.stopPropagation();
});

There are some oddities in your code that could defintiely be streamlined First you pass an element to the handler...then take properties of that elemnt to create a selector to find exactly the same element again in the DOM

var cellId = element.id;
$('#' + cellId)

Can be simplified to

$(element);// doesn't require searching for the ID

And can also be stored as a variable instead of doing the same selector over and over

var $el = $(element);
$el.off('click');
var oldCellContent = $el.text();

These simplifications are more efficient and easier to read

The problem is you rewrite alaways content of div because you don't stop propagations.

I fix your problem with this code:

    var oldCellContent = $('#elementId').text();
     var newButtons = '<button class="btn btn-default complete">Complete?</button><button class="btn btn-default  delete">X</button>';
    $("#elementId").click(function(){
    $(this).html(newButtons);
    });
$("#elementId").on("click","button.complete",function(e){

        console.log('The complete function fired.');
        $('#elementId').text('Completed');
        e.stopPropagation();

    });
    $("#elementId").on("click","button.delete",function(e){
        console.log('The cancel function fired.');
        $('#elementId').text(oldCellContent);
        e.stopPropagation();
    });

The simplest solution to all of this is wrap the "New" text in it's own element and put the "show buttons" click handler on that element and simultaneously hide "new".

Code will be much simpler and there won't be any propagation issues or need to use off() and then add same handler again.

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