inhan
inhan

Reputation: 7470

JQuery: custom function for multiple selectors, some inside others - selects the outermost one only

I have been reading here and there about multiple JQuery selectors but I couldn't get the answer I was looking for.

$.fn.extend({
    sayHi:function() {
        console.log($(this).attr('class') + ' says hi');
    }
}
$('.class1,.class2').sayHi();

The last selector always calls the outermost item among the listed ones. Here's what happens:

<div class="class1"><!-- only this one gets selected -->
    <div class="class2"></div>
</div>

What is the most elegant way to make it select all the indicated selectors no matter whether they're wrapped by any other selector(s) indicated?

EDIT:

I know I can use it like

$('.class1').sayHi();
$('.class2').sayHi();

but I'm willing to bind it into a single call (I'm actually using more than 2 selectors).

Upvotes: 0

Views: 686

Answers (3)

Anthony
Anthony

Reputation: 37045

If I understand correctly, you might have the following html:

<div class="class1" id="outer1">
    <div class="class2 inner">
        <div class="class1 inner">
            <div class="class2 inner">
            </div>
        </div>
    </div>
</div>
<div class="class2" id="outer2">
    <div class="class1 inner">
        <div class="class2 inner">
            <div class="class1 inner">
            </div>
        </div>
    </div>
</div>

And you want a selector like:

$(".class1, .class2");

But filtered so that only outer1 and outer2 get selected, not those of class inner, is that right?

The following will select all elements of either class and then exclude any elements descendent from either class, thus only leaving the highest ancestor of either class, ie the outer-most element:

$(".class1, .class2").not(".class1 *, .class2 *")

Upvotes: 0

Felix Kling
Felix Kling

Reputation: 816334

You problem is not with the multiple selector but with how attr works.

First, inside the plugin method, this already refers to a jQuery object, there is not need to pass it to jQuery again.
Secondly, attr [docs] will always return the value of the first of the selected elements (emphasis mine):

Get the value of an attribute for the first element in the set of matched elements.

this references the two selected elements, the first one will always be .class1.

You therefore have to iterate over the selected elements and access the attribute of each element individually, just as @Eli shows in his answer. This is a common pattern for jQuery plugins.

The jQuery Plugins/Authoring page might be worth reading as well.

Upvotes: 1

Eli
Eli

Reputation: 17825

Is this what you are trying to do?

(function ($) {
    $.fn.sayHi = function() {
        return this.each(function() {
            console.log($(this).attr('class') + ' says hi');
        });
    };
})(jQuery);

$('.class1, .class2').sayHi();

Upvotes: 2

Related Questions