Reputation: 246
I have a list inside a container which has classes assigned to li
based on its type. I want to trigger custom event of the form click.list.type
. So I've written the code as shown in below:
HTML
<div class="row" id="container">
<ul class="list-group" id="group">
<li class="list-group-item type-a">
<a href="#">Item 1 - Type A</a>
</li>
<li class="list-group-item type-a">
<a href="#">Item 2 - Type A</a>
</li>
<li class="list-group-item type-b">
<a href="#">Item 3 - Type B</a>
</li>
<li class="list-group-item type-b">
<a href="#">Item 4 - Type B</a>
</li>
</ul>
</div>
JS
//This code will be not be available to user
$('#container').on('click', 'li > a', function(event){
event.preventDefault();
event.stopPropagation();
var type = $(event.target).closest('li').hasClass('type-a') ? 'typea' : 'typeb';
triggerMyEvents.call(this,event,'click', type);
})
function triggerMyEvents(event, name, type){
if(event.target.tagName !== 'A'){
return;
}
$(this).trigger($.Event(name+'.'+type));
}
//API for user
$('#container').on('click.typea', function(event){
// if(event.target.tagName !== 'A'){
// return;
// }
alert("Type A: " +event.target.tagName);
}).on('click.typeb', function(event){
// if(event.target.tagName !== 'A'){
// return;
// }
alert("Type B: " +event.target.tagName);
});
CSS
html,body{
height:100%;
}
#container{
height:100%;
background: red
}
#group{
background: green;
height: 300px;
}
Everthing works as expected except that on click of ul
(the green area) or div#container
(red area),the above events are triggered. Putting a check on listeners solves the problem (the commented code). But I don't want to repeat writing the check code where ever the listener is used.
Can anybody help me out?
JS BIN: http://jsbin.com/xelojujeva/1/
Upvotes: 1
Views: 80
Reputation: 82136
This isn't anything to do with event bubbling, this is simply down to how event namespacing works in jQuery. The purpose of a namespace is to allow filtering on events e.g.
$('#container').on('click.myPlugin', function() {
// code specific to myPlugin
});
...
// trigger myPlugin click event handler only
$('#container').trigger('click.myPlugin');
However, the filtering works from top-down approach therefore trigger('click')
would fire all registered click event handlers (regardless of namespace) - that's pretty much what's happening here. There are a number of ways to fix this, the most obvious one is to apply the exact same filter you applied in the previous click
handler
$('#container').on('click.typeA', 'li > a', ...).on('click.typeB', 'li > a', ...);
However, a better approach would be to not apply the second events to the #container
element at all but instead call a function
//This code will be not be available to user
var self = this;
$('#container').on('click', 'li > a', function(evt){
evt.stopImmediatePropagation();
var type = $(event.target).closest('li').hasClass('type-a') ? 'typea' : 'typeb';
self[type + 'Clicked'](evt);
});
function typeaClicked(evt) {
alert('Type A: ' + evt.target.tagName);
}
function typebClicked() {
alert('Type B: ' + evt.target.tagName);
}
Upvotes: 1
Reputation: 246
Solved the problem by using type.click.list
in place of click.list.type
//This code will be not be available to user
$('#container').on('click', 'li > a', function(event){
event.preventDefault();
event.stopPropagation();
var type = $(event.target).closest('li').hasClass('type-a') ? 'typea' : 'typeb';
triggerMyEvents.call(this,event, type, 'click');
})
function triggerMyEvents(event, type, name){
if(event.target.tagName !== 'A'){
return;
}
$(this).trigger($.Event(type+'.list.'+name));
}
//API for user
$('#container').on('typea.list.click', function(event){
alert("Type A: " +event.target.tagName);
}).on('typeb.list.click', function(event){
alert("Type B: " +event.target.tagName);
});
Upvotes: 0