tags:

views:

44

answers:

2

HTML:

<div class="parent">
    <div class="child1" >
    </div>
    <div class="child2">
    </div>
</div>

<a class="btn1">customClick.btn1</a>
<a class="btn2">customClick.btn2</a>

JavaScript:

 jQuery('div.child1')
    .bind('customClick.btn1', function () {
        alert('child1 reacted to customClick.btn1');
    });


 jQuery('div.child2')
    .bind('customClick.btn2', function () {
        alert('child2 reacted to customClick.btn2');
    });

 jQuery('div.parent')
    .bind('customClick.btn1', function (e) {
      alert('parent reacted to customClick.btn1');
    })
    .bind('customClick.btn2', function (e) {
       alert('parent reacted to customClick.btn2');
    });

jQuery('a.btn1')
    .click(function(){
        jQuery('div.child1').trigger('customClick.btn1');
    });

jQuery('a.btn2')
    .click(function(){
        jQuery('div.child2').trigger('customClick.btn2');
    });

When I click a.btn1, as expected, the customClick.btn1 event is handled by div.child1 and not div.child2. What is not expected is that the customClick event bubbles and triggers the handlers on div.parent for both customClick.btn1 and customClick.btn2. Is this right? Is there any way to have custom events bubble with their namespace? In other words, when customClick.btn1 is triggered, not all parent handlers for customClick are handled, just ones that handle customClick.btn1.

+2  A: 

Looking at the docs, it looks like when you're doing namespacing, the part before the . is the event type. So that is the event that is being triggered.

As such, the .parent element has 2 customClick event types bound to it. That is why they both fire.

From the docs: http://api.jquery.com/bind/

If the eventType string contains a period (.) character, then the event is namespaced. The period character separates the event from its namespace. For example, in the call .bind('click.name', handler), the string click is the event type, and the string name is the namespace. Namespacing allows us to unbind or trigger some events of a type without affecting others.

It would seem to be a reasonable expectation that the namespace would be considered when the event bubbles, but apparently not.

You could instead check the e.target.className to see which element was triggered. There must also be a way to get the namespacing that you could test from the event object.


EDIT:

Looks like you could test for the namespace of the event object like this:

if(e.handleObj.namespace === 'btn1')

EDIT:

As @Nick Craver demonstrated in the comment below, the namespace is considered in bubbling when the namespaced events are not bound to the children. As such (one way or the other) it seems like a bug.

Either way, you should still be able to test for the namespace as noted above since the property does seem to be present in the Event object in both cases.

patrick dw
This complicates it a bit though: http://jsfiddle.net/nick_craver/bNbpN/ if the `.child1` and `.child2` *aren't* bound, it does bubble correctly, with a namespace, it's the first bound handler that doesn't pass it on, where native bubbling does, I'm not sure of the *intended* behavior here, but seems like a bug.
Nick Craver
@Nick - Well, that *is* strange. It does seem to me that the expected behavior would be to have the namespace considered when bubbling. After all, if one took the time to give a namespace to the events on `.parent` as well as the descendants, it would seem a reasonable expectation that a matched namespace would be desired in event handling, even when bubbling. I'd agree that it seems like a bug.
patrick dw
@patrick dw - Testing for the namespace does not actually help you. If you click a.btn1, div.parent will handle both 'customClick.btn1' and 'customClick.btn2' with their respective namespaces. Using firebug, you can see that both handlers are entered with the namespace they are supposed to handle and the target property for both is div.child1. So big question is why is the div.child1 triggerring 'customClick.btn2' in this case. Also I am going to post a temporary solution that gets dont what I am trying to do. Hopefully, one beautiful day, I will return to the namespaced event syntax.
Adrian Adkison
@Adrian - Ok, I see what you mean. Both events are bubbling, so each has its own namespace that is tested, and then firing.
patrick dw
+1  A: 

Html

<div class="parent">
    <div class="child1" >
    </div>
    <div class="child2">
    </div>
</div>

<a class="btn1">customClick.btn1</a>
<a class="btn2">customClick.btn2</a>

jQuery

 jQuery('div.child1')
    .bind('customClick', function (e) {
        if(e.namespace == 'btn1'){
          console.log('child1 reacted to customClick.btn1');
        }
    });


 jQuery('div.child2')
    .bind('customClick', function (e) {
       if(e.namespace == 'btn2'){
          console.log('child2 reacted to customClick.btn2');
       }
    });

 jQuery('div.parent')
    .bind('customClick', function (e) {
      if(e.namespace == 'btn1'){
          console.log('parent reacted to customClick.btn1');
      }
      if(e.namespace == 'btn2'){
          console.log('parent reacted to customClick.btn2');
      }
    })


jQuery('a.btn1')
    .click(function(){
        jQuery('div.child1').trigger({type:'customClick',namespace:'btn1'});
    });

jQuery('a.btn2')
    .click(function(){
        jQuery('div.child2').trigger({type:'customClick',namespace:'btn2'});
    });

While this works, I would love to do it the way I was doing it before. I opened up a ticket with jQuery. Ticket #6913 Thanks Nick Craver and patrick dw for helping confirm the issue.

Adrian Adkison
I was just about to ask if you were going to file a bug report. Definitely needs a fix.
patrick dw