Oam Psy
Oam Psy

Reputation: 8663

Unable to click child element as parent is always in focus

I have a list of buttons, and on hover, a small (x) appears in the top right corner of the button. I am trying to attach a click handler on the (x), however, when ever i click it, the actually button is clicked, rather than the (x).

Code:

btnArray.forEach(function (button) {

    const btn = document.createElement('div');
    btn.type = 'button';
    btn.value = button.name;
    btn.onClick = evt => {
        // do soemthing on click
    }

    btn.onmouseover = function(e) {
        var me = d3.select(btn);
        me.append('div')
            .classed({'btn-close': true})
            .append('div')
            .classed({'btn-x-icon': true})
            .text('x')
            .on('click', function() {
                alert('you clicked on the x!');
            });
    }

    btn.onmouseout = function(e) {
        var me = d3.select(btn);
        me.selectAll('.btn-close')
            .remove();
    }

    btn.appendChild(document.createTextNode(button.name))

});

Even when i place my mouse over the (x), the parent button still appears to be in focus.


UPDATE

I can click on the icon by increasing the z-index of the (x) icon.

Howvever, when clicking, the (x) onclick is called as well as the main btn.onclick call.


UPDATE

Markup:

<button type="button" value="Checkout" class="btn btn-primary">
    Check out

    <div class="btn-close">
        <div class="btn-x-icon">x</div>
    </div>

</button>

Upvotes: 1

Views: 1367

Answers (2)

Nope
Nope

Reputation: 22339

Using event.target you can ensure you only respond to the correct element being clicked.

In the below examples I only added identifiers so I can attach the click events easier for demonstration but the code inside the event handlers is applicable as is to your code off course.

Also, note that I did not specify a event parameter in the handler because event is assigned automatically, when specifying a parameter for the event such as 'click', function(evt) you are now using the event object as specified by d3 which may or may not be the same event object.

var button = document.getElementById("button");
button.addEventListener('click', function() {
  if (event.target == this) {
    console.log('button clicked')
  }
})

var button = document.getElementById("close");
button.addEventListener('click', function() {
  console.log('close clicked')
})
#close {
  background-color: red;
}
<button id="button" type="button" value="Checkout" class="btn btn-primary">
    Check out
    <div id="close" class="btn-close">
        <div class="btn-x-icon">x</div>
    </div>

</button>

Alternatively you can use stopPropagation

var button = document.getElementById("button");
button.addEventListener('click', function() {
  console.log('button clicked')
})

var button = document.getElementById("close");
button.addEventListener('click', function() {
  event.stopPropagation();
  console.log('close clicked')
})
#close {
  background-color: red;
}
<button id="button" type="button" value="Checkout" class="btn btn-primary">
    Check out
    <div id="close" class="btn-close">
        <div class="btn-x-icon">x</div>
    </div>
</button>

Upvotes: 1

jmtalarn
jmtalarn

Reputation: 1723

You should stop the propagation event on click. The event, once is produced, is propagated to all the inherent elements. You should stop that propagation in order to avoid execute more handlers for that event.

More about that Event bubbling (in the other way) and propagation http://www.javascripter.net/faq/eventbubbling.htm https://www.sitepoint.com/event-bubbling-javascript/

btnArray.forEach(function (button) {

    const btn = document.createElement('div');
    btn.type = 'button';
    btn.value = button.name;
    btn.onClick = evt => {
        // do soemthing on click
    }

    btn.onmouseover = function(e) {
        var me = d3.select(btn);
        me.append('div')
            .classed({'btn-close': true})
            .text('x')
            .on('click', function(evt) {
                evt.stopPropagation();
                alert('you clicked on the x!');
            });
    }

    btn.onmouseout = function(e) {
        var me = d3.select(btn);
        me.selectAll('.btn-close')
            .remove();
    }

    btn.appendChild(document.createTextNode(button.name))

});

Upvotes: 0

Related Questions