9

When delegating events using .on how do I target child elements:

I have tried: childSelector =

  • >*
  • >:nth-child(n)

But nothing is selected when I start with >.

$(selector).on(event, childSelector, handler);

Sometimes I want to target a direct child, sometimes I don't: (pseudo code)

var func = function(selector, subSelector) {
    $(selector).on("click", subSelector, function() {
        alert("my subSelector is clicked");
    });
}

func("#wrapper", "direct-child-selector");
func("#wrapper", ".some .other > .selector:first");

Thats why I'm asking for a selector and not a fix.

Andreas Louv
  • 46,145
  • 13
  • 104
  • 123
  • Your edit doesn't make any sense. A *child* is an element which is an immediate descendant of the element... e.g. `child.parentNode === parent`. An "*indirect child*" is merely a descendant; e.g. `descendant.parentNode.parentNode.parentNode(etc) === ancestor`. Because of how event bubbling works, if the delegated handler receives an event, you can *guarantee* the target of the event was a descendant. – Matt Mar 29 '12 at 09:50

4 Answers4

8

You could check within the handler whether the element is a child of the element the event handler was delegated to;

$(selector).on("event", '*', function (e) {
    if (e.target.parentNode === e.delegateTarget) {
        // Woo!
    }
});

See e.delegateTarget. Its worthy to note that e.delegateTarget was introduced in jQuery 1.7, so won't work on older versions.

In regards to your second edit, in it's current form the selectors are ambiguous; there's no way for you to, in code and in its current form, detect whether the selector passed is intended to be a child only selector. You can either introduce another parameter to indicate whether it's intended to be a child only selector, or add a > to the start of the selector (e.g.) and check for that;

var func = function(selector, subSelector, isChild) {
    $(selector).on("click", subSelector, function(e) {
        if (isChild && e.parentNode == e.delegateTarget || !isChild) {
             alert("my subSelector is clicked");
        }
    });
}

func("#wrapper", "direct-child-selector", true);
func("#wrapper", ".some .other > .selector:first" /* , `false` is optional */);

Or:

var func = function(selector, subSelector) {
    if (subSelector.charAt(0) === '>') {
        subSelector = selector + subSelector;
    }

    $(selector).on("click", subSelector, function(e) {
        alert("my subSelector is clicked");
    });
}

func("#wrapper", "> direct-child-selector");
func("#wrapper", ".some .other > .selector:first");
Matt
  • 74,352
  • 26
  • 153
  • 180
  • wow. didn't know about `delicateTarget`. But i still have a problem see edited question – Andreas Louv Mar 29 '12 at 09:45
  • ok thanks for your help. So there doesn't seem to a selector where you can assure to select the direct children and make room for selecting anything else with out a workaround. – Andreas Louv Mar 29 '12 at 11:05
  • I believe it needs to be `this.parentNode` rather than `e.parentNode`. Perhaps `e.target.parentNode` also works. – Steven Lu Jul 07 '12 at 17:05
3

This worked for me.

$('#container').on('click', '> .children', function(){
...
})
alexndm
  • 2,899
  • 5
  • 24
  • 25
2

One way to only delegate events triggered on direct children is to provide a full selector to on(), including the part that matches the parent element:

$(selector).on("event", selector + " > *", handler);
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • Is not `*` defined by W3C as something to "match all elements"? http://www.w3.org/TR/CSS2/selector.html#pattern-matching – Lee Goddard Jun 28 '14 at 11:14
  • @LeeGee, yes, it is. Coupling it with a child selector (e.g. `"div > *"`) allows to match all the direct children of a given set of elements. – Frédéric Hamidi Jun 28 '14 at 11:47
0

All you need is:

childSelector = "*";

if it's supposed to match any child of the selector. It searches only in the scope of the selector.

Joel Lundberg
  • 916
  • 5
  • 6
  • 2
    That will match all *descendants*. An element is a child if it's an **immediate** descendant. – Matt Mar 29 '12 at 09:34