Roman Mazur
Roman Mazur

Reputation: 512

Force jQuery to search only in a subtree of a specified element

Is it possible to somehow reconfigure jQuery to search only in a subtree of a specified element?

I need to do something like this:

var lockToSubtree = function (jq) {
        //reconfigure jq
        return reconfiguredJQuery;
    },

    myJQuery = lockToSubtree(jQuery, '.my-namespace');

So I have my own instance of jQuery which searches elements only inside '.my-namespace'.

To illustrate my needs here is a sample HTML:

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
    <div id="divOne" class="someClass"></div>
    <div class="my-namespace">
        <div id="divTwo" class="someClass"></div>
    </div>
</body>
</html>

So I can later use in my code:

var $el = myJQuery('.someClass');

And it will search .someClass only in a subtree of a .my-namespace. So it will return only div#divTwo and div#divOne will be skipped because it is not located under a subtree of .my-namespace.

The point is, that I need it to keep searching in a subtree of .my-namespace also when using jQuery functions like .closest() etc., see the final code snippet:

var $myJQuery = lockToSubtree(jQuery, '.my-namespace'),
    $el = myJQuery('.someClass'); // $el is the #divTwo element

$el.closest('body'); // finds nothing, because body is not located under .my-namespace

UPDATE:

I agree with @Keith that it is probably not possible to reconfigure jQuery to search in some subtree also with .closest method, which searches upwards. Thus I will be OK with searching in a subtree only when the search direction is down.

I would like to emphasize that I need the jQuery function to have the same functionality like original jQuery (properties like jQuery.fn etc.).

The real life scenario: I need to scope some third party library in our project so it would not affect HTML until some level of depth. The library is a one line of a JavaScript minified code using global jQuery object. All I need is to wrap it in self-invoking function and pass to it some modification of jQuery function which searches only in some subtree of a DOM, but contains all the properties as normal jQuery.

This code maybe explains it better:

(function (jQuery) {
    // I am passing jQuery through parameter
    // ... here is the library code
}(/* here I want to inject modified jQuery */));

Upvotes: 4

Views: 2314

Answers (3)

Roman Mazur
Roman Mazur

Reputation: 512

I can't accept @Dormouse's or @ArunPJohny's answers because both returns simple functions which do not have another jQuery functions inside like jQuery.fn, so it is impossible to use their solutions.

Here is what I came up after reading @ArunPJohny's code and what works fine for me:

(function (jQuery) {
    // third party library using my own modified jQuery function
}((function ($) {

    var $wrapper = $('.cms-bootstrap'),
        scopedjQuery = function (selector) {
            return $(selector, $wrapper);
        };

    // Copy all jQuery properties into
    // scopedjQuery so they can be used later
    for (var k in $) {
        if ($.hasOwnProperty(k)) {
            scopedjQuery[k] = $[k];
        }
    }

    return scopedjQuery;

}(window.jQuery.noConflict()))))

Upvotes: 0

Dormouse
Dormouse

Reputation: 5198

You can create a wrapper function for the jQuery selector like so:

$Q = function (select, opts) {
    return $(".my-namespace", opts).find(select);
};

And then just call your wrapper as you would jQuery $Q(".element").children() etc....

jSFiddle here

You can do this with closest to pass a context:

var namespace = $(".my-namespace").get()[0];

$(".foo").closest("p.bar", namespace);

Upvotes: 6

Keith
Keith

Reputation: 994

You are asking for something that jQuery does not support, since .closest() will search up the DOM tree all the way to the document. Something terribly expensive, but that will do what you are asking is to clone the .my-namespace into a document fragment. Then, .closest() will not go higher than the document fragment because fragments do not have parents.

I would suggest writing your own .closest() method to make sure you stop where you want, and then use Dormouse's answer for searching down.

Upvotes: 3

Related Questions