Dobz Dobz - 5 months ago 7
jQuery Question

DIVs click event wrongly triggering other DIVs click event

I am trying to bind the click events of div elements to show their respective modals.

I pass through the IDs of each element, and the function reports it is binding the correct ID.

When I actually click on a div though, the click event is always triggered for the final ID.

I have inspected the HTML of the DIVs, and they all have the right IDs.

<div id="e800" data-target="#event800" class="event" data-eid="800">
<p>Click Me</p>
<div id="event800" style="display: none;" role="dialog" tabindex="1" class="modal">
<p>I am another DIV</p>
</div>
</div>

<div id="e801" data-target="#event801" class="event" data-eid="801">
<p>Click Me</p>
<div id="event801" style="display: none;" role="dialog" tabindex="1" class="modal">
<p>I am another DIV</p>
</div>
</div>

<div id="e802" data-target="#event802" class="event" data-eid="802">
<p>Click Me</p>
<div id="event802" style="display: none;" role="dialog" tabindex="1" class="modal">
<p>I am another DIV</p>
</div>
</div>


function BindEvents(ids) {

for(var i = 0, l = ids.length; i < l; i++) {
/* ID of element - ex: #e800 */
var e = "#e" + ids[i];

/* ID of element I want to show - ex: #event800 */
var id = $(e).data('target');

/*
This console.log outputs the correct e and id. Ex:
"Binding click of #e800 to show #event800"
*/
console.log("Binding click of " + e + " to show " + id);

$(e).on('click', function(ev) {
/*
This console.log outputs the e and id of the very last div.
I click #e800 and the output for this is :
"Click event of #e802 now showing #event802"
*/
console.log("Click event of " + e + " now showing " + id);
$(id).show();
$('#backdrop').show();
});

/*
$(id) element is a child of the $(e) element.
If we do not call ev.stopPropagation() then
the click will also be triggered in $(e).
This would cause the modal to reshow directly
after being hidden.
Which means once clicked, it would never hide.
*/

$(id).on('click', function(ev) {
ev.stopPropagation();
$(id).hide();
$('#backdrop').hide();
});
}
}


The solution to my problem was in the Duplicate question.
This is my updated solution. (Although I will probably change to my Accepted Answer, and bind a class).

function BindEvents(ids) {

for(var i = 0, l = ids.length; i < l; i++) {

let e = "#e" + ids[i];
let id = $(e).data('target');

$(e).on('click', function(ev) {
$(id).show();
$('#backdrop').show();
});

$(id).on('click', function(ev) {
ev.stopPropagation();
$(id).hide();
$('#backdrop').hide();
});
}
}

Answer

I would recommend putting a using the class on all of them (i.e. class="showModalOnClick") "edit" -- possibly change it to suit your needs better.

Then, use a single bind event :

    // bind to document instead of directly to the class in case you have 
    // some of the items to click being added after the document is loaded.
    $(document).on('click','.edit',function(){
        var $this = $(this);
        var e = $this.attr('id');
        var id = $this.data('target');

        // This console.log outputs the e and id of the very last div.
        // I click #e800 and the output for this is :
        // "Click event of #e805 now showing #event805"
        console.log("Click event of " + e + " now showing " + id);
        $(id).show();
        $('#backdrop').show();

        // $(id) element is a child of the $(e) element.
        // If we do not call ev.stopPropagation() then
        // the click will also be triggered in $(e).
        // This would cause the modal to reshow directly
        // after being hidden.
        // Which means once clicked, it would never hide.
        // .one will run this event once and unbind after
        $(id).one('click', function(ev) {
            ev.stopPropagation();
            $(id).hide();
            $('#backdrop').hide();
        });
    });
Comments