Frage

I am having an issue very similar to: "Jquery 'click' not firing when icon is on button" however the resolution for that post is not providing a solution for me, so I think something different may be going on.

The essential problem is that I have a button with an icon in it. When I click on the button (e.g. the text) the event target is the button element; however when I click on the icon, the event target is the icon object. This unfortunately is extremely annoying as I am storing data values on my button that I would like access to.

Here is the HTML:

<button class="btn btn-success vote-button" id="btnUpVote" type="button" data-vote="1">
    <i class="fa fa-thumbs-up"></i>
    Up Vote!
</button>

<button class="btn btn-danger vote-button" id="btnDownVote" type="button" data-vote="-1">
    <i class="fa fa-thumbs-down"></i>
    Down Vote!
</button>

And here is the Javascript:

function sendVote(event) {
    var $btn = $(event.target);
    console.log(parseInt($btn.data('vote'));
    console.log($btn.prop('tagName'));
}

$('body').on('click', 'button.vote-button', sendVote);

Clicking on the text ("Up Vote!" or "Down Vote!") results in the following console output:

1
BUTTON
-1 
BUTTON

Clicking on the icon (, etc.) results in the following console output:

NaN
I
NaN
I

Even though I've registered the handle on elements with selector "button.vote-button". Does anyone know why this is happening? I'd hate to have to give data attributes to the icons.

War es hilfreich?

Lösung 3

It's caused by event propagation. You click on the icon, which is inside the button, so the click event propagates up through the DOM from the icon, to the button, all the way up to the document. This results in your click event handler code being executed.

If the issue is that you just want the reference to the button every time that code runs, but you still want it to trigger when you click on the icon instead of the text, you just need to use this rather than event.target:

var $btn = $(this);
...

jQuery will make sure that this always refers to the button, even if the actual event.target element is an element inside it.

Andere Tipps

Use event.currentTarget which is always the object listening for the event; event.target is the actual target that received the event which is not what you want in this case since it could be the icon.

With event.currentTarget if the user clicks on the icon, it'll bubble the event up to the object listener which is the button in your case. If the user clicks the button it'll still work because again the object listener is your button.

Simple CSS solution:

button > * {
  pointer-events: none;
}

update this because $(event.target) is not always button for this you have to use ternary operator as suggested or replace $(event.target) with $(this) which is always button in the context of selector:

function sendVote(event) {
    event.stopPropagation(); 
    var $btn = $(event.target).is('button') ? $(event.target) : $(event.target).parent();
    console.log(parseInt($btn.data('vote')));
    console.log($btn.prop('tagName'));
}
$(function () {
    $('body').on('click','button.vote-button', sendVote);
});

Demo fiddle


or with $(this) which is always button because the event is bound to it and if you click on any child of it then event will bubble up to the dom tree and event bound to button gets executed:

function sendVote(event) {
    var $btn = $(this);  // <-----------------change just here
    console.log(parseInt($btn.data('vote')));
    console.log($btn.prop('tagName'));
}

How bout just checking within the function if the tagname is I, and if it is, getting the parent as your $btn. http://jsfiddle.net/jFIT/qZgYU/3/

$('body').on('click', 'button.vote-button', function() {
 var $btn = $(this).prop('tagName').toLowerCase() == "i" ? $(this).parent() : $(this);
 console.log(parseInt($btn.data('vote')));
 console.log($btn.prop('tagName'));
});
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top