JQuery individual descendants (filter out all parents in the result set)

I need a method to filter out all the elements that are the parents of other elements in the result set. I tried to write a plugin:

jQuery.fn.distinctDescendants = function() {
    var nodes = [];
    var result = this;

    jQuery(result).each(function() {
        var node = jQuery(this).get(0);
        if(jQuery(node).find(result).length == 0) {
            nodes.push(node);
        }
    });

    return nodes;
};

      

When I run the following command this example page :

jQuery('body, textarea').distinctDescendants();

      

I am getting (wrong) result:

[body.contact-page, textarea, textarea]

      

This is wrong because the body is the parent of at least one other element in the result (both text boxes). Therefore, the expected result would be:

[textarea, textarea]

      

What's wrong here?

0


source to share


3 answers


Why aren't you using jQuery('body > input')

this instead?

You can use the following (verbose) code to achieve your desired result; it should work as a replacement for your plugin.



jQuery.fn.distinctDescendants = function() {
    var nodes = [];
    var parents = [];

    // First, copy over all matched elements to nodes.
    jQuery(this).each(function(index, Element) {
        nodes.push(Element);
    });

    // Then, for each of these nodes, check if it is parent to some element.
    for (var i=0; i<nodes.length; i++) {
        var node_to_check = nodes[i];
        jQuery(this).each(function(index, Element) {

            // Skip self comparisons.
            if (Element == node_to_check) {
                return;
            }

            // Use .tagName to allow .find() to work properly.
            if((jQuery(node_to_check).find(Element.tagName).length > 0)) {
                if (parents.indexOf(node_to_check) < 0) {
                    parents.push(node_to_check);
                }
            }
        });
    }

    // Finally, construct the result.
    var result = [];
    for (var i=0; i<nodes.length; i++) {
        var node_to_check = nodes[i];
        if (parents.indexOf(node_to_check) < 0) {
            result.push(node_to_check);
        }
    }

    return result;
};

      

+1


source


Your method seems to be OK, but your example is probably wrong. You said -

jQuery('body, input').distinctDescendants();

I am getting (wrong) result:

[body.contact-page, textarea, textarea]

      



Why are you getting textarea if it's not in the selector? Also be careful with this method. Remember -

jQuery ('div, input'). distinctDescendants (); means that some input is inside the div in question and some outside. While the result is not unpredictable, it seems difficult to guess. So most of the time, try using a selector that has a class name or ID.

Give us your feedback ... I feel like the function is ok.

+1


source


I think this is what you expect from

jQuery('body, input').filter(function(){if($(this).children().length >0) return false; else return true; })

      

or maybe rather

jQuery('body, input, textarea').filter(function(){if($(this).children().length >0) return false; else return true; })

      

and this will only return textareas (as you want in the example)

jQuery('body, textarea').filter(function(){if($(this).children().length >0) return false; else return true; })

      

UPDATE

so you want something like this

var elems = 'textarea';

jQuery('body, '+ elems )
      .filter(function(){
           if($(this).find(elems ).length >0) 
               return false; 
           else return true; 
       })

      

which returns

[textarea, textarea]

      

0


source







All Articles