Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to filter elements returned by QuerySelectorAll

Tags:

javascript

I'm working on a javascript library, and I use this function to match elements:

$ = function (a) {     var x;     if (typeof a !== "string" || typeof a === "undefined"){ return a;}          //Pick the quickest method for each kind of selector     if(a.match(/^#([\w\-]+$)/))     {         return document.getElementById(a.split('#')[1]);     }     else if(a.match(/^([\w\-]+)$/))     {         x = document.getElementsByTagName(a);     }     else     {         x = document.querySelectorAll(a);     }          //Return the single object if applicable     return (x.length === 1) ? x[0] : x; }; 

There are occasions where I would want to filter the result of this function, like pick out a div span, or a #id div or some other fairly simple selector.

How can I filter these results? Can I create a document fragment, and use the querySelectorAll method on that fragment, or do I have to resort to manual string manipulation?

I only care about modern browsers and IE8+.

If you want to look at the rest of my library, it's here: https://github.com/timw4mail/kis-js

Edit:

To clarify, I want to be able to do something like $_(selector).children(other_selector) and return the children elements matching that selector.

Edit:

So here's my potential solution to the simplest selectors:

tag_reg = /^([\w\-]+)$/; id_reg = /#([\w\-]+$)/; class_reg = /\.([\w\-]+)$/;  function _sel_filter(filter, curr_sel) {     var i,         len = curr_sel.length,         matches = [];          if(typeof filter !== "string")     {         return filter;     }      //Filter by tag     if(filter.match(tag_reg))     {         for(i=0;i<len;i++)         {             if(curr_sell[i].tagName.toLowerCase() == filter.toLowerCase())             {                 matches.push(curr_sel[i]);             }         }     }     else if(filter.match(class_reg))     {         for(i=0;i<len;i++)         {             if(curr_sel[i].classList.contains(filter))             {                 matches.push(curr_sel[i]);             }         }     }     else if(filter.match(id_reg))     {         return document.getElementById(filter);     }     else     {         console.log(filter+" is not a valid filter");     }          return (matches.length === 1) ? matches[0] : matches;      } 

It takes a tag like div, an id, or a class selector, and returns the matching elements with the curr_sel argument.

I don't want to have to resort to a full selector engine, so is there a better way?

like image 690
timw4mail Avatar asked Jul 22 '11 13:07

timw4mail


People also ask

How do I get values from querySelectorAll?

To retrieve all copies of a specific element, you can simply pass the name of the element as its argument. You can also select elements by other attributes like target or value : // return all elements with target="_blank" document. querySelectorAll("[target=_blank]"); // return all elements with value="red" document.

What does the querySelectorAll () method do?

The querySelectorAll() method in HTML is used to return a collection of an element's child elements that match a specified CSS selector(s), as a static NodeList object. The NodeList object represents a collection of nodes. The nodes can be accessed by index numbers. The index starts at 0.

What type does querySelectorAll return?

The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.


1 Answers

I don't think I get the question right. Why would you want to "filter" the result of querySelectorAll() which infact, is some kind of a filter itself. If you query for div span or even better #id div, those results are already filtered, no ?

However, you can apply Array.prototype.filter to the static result of querySelectorAll like follows:

var filter   = Array.prototype.filter,     result   = document.querySelectorAll('div'),     filtered = filter.call( result, function( node ) {         return !!node.querySelectorAll('span').length;     }); 

That code would first use querySelectorAll() to query for all <div> nodes within the document. Afterwards it'll filter for <div> nodes which contain at least one <span>. That code doesn't make much sense and is just for demonstrative purposes (just in case some SO member wants to create a donk comment)

update

You can also filter with Element.compareDocumentPosition. I'll also tell if Elements are disconnected, following, preceding, or contained. See MDC .compareDocumentPosition()

like image 197
jAndy Avatar answered Sep 26 '22 02:09

jAndy