9

I have an Element. I would like to check whether it meets a particular query, eg ('.someclass') in the same kind of style as querySelector.

This isn't as easy as it sounds. Element.querySelectorAll and Element.querySelector only work on descendents of the element in question. Not the element itself.

var p = document.querySelector('p')

Note: The line above is for illustration purposes only. In real life, I've actually found the element by some other means.

p.querySelector('p')

Returns null. Because querySelector only operates on descendents.

I could do:

p.parentNode.querySelector('.someclass')

But that would return the first child of the element's parent, which may be a different element. This code would fail, for example, if 'p' was the second child of the parent.

How can I check if an element itself meets a query?

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • `querySelector` operates on descendants, not children. – Asad Saeeduddin Nov 15 '12 at 11:50
  • @Asad: Children and descendants are generally used interchangeably, much in the same way that parent and antecedents are. If you really like I can change the terminology. – mikemaccana Nov 15 '12 at 11:51
  • I'm not sure why this would be useful: why can't you just query the `className` or `Attributes` of the given Element? – KooiInc Nov 15 '12 at 11:58
  • @KooiInc I could indeed write something that checks className, ID, Attributes etc. But the resultant code would seem like a copy of something that already exists in the form of querySelector. – mikemaccana Nov 15 '12 at 12:00
  • Well, the alternative looks more expensive: one way or another you'll have to loop a collection of Nodes and compare them to the given node to be sure you're operating on the right node. Having the node already available, querying its attributes/properties seems more obvious. One *can* drive a nail into wood using a screw driver, but a hammer is more suitable. – KooiInc Nov 15 '12 at 12:08
  • @KooiInc Since it's a fairly common problem I guessed there was a native method to take care of this without unnecessarily referring to extra nodes or rewriting the syntax for querySelector. And there is - see the answers. – mikemaccana Nov 15 '12 at 12:10
  • It's ok with me ofcourse, and I like the [prefix]MatchesSelector approach, but using it you have to check for the right method (or prefix) to use before being able to apply it. Still looks a bit like a screwdriver to hammer a nail ;) – KooiInc Nov 15 '12 at 12:29
  • @KooiInc It's a prefixed hammer :^). – mikemaccana Nov 15 '12 at 13:03

4 Answers4

11

You can use the matches() method.

Support can be found at http://caniuse.com/matchesselector


But since it is still a draft, all browsers implement it with a prefix (it was a draft in 2012)

  • element.msMatchesSelector( selector ) (IE)
  • element.mozMatchesSelector( selector ) (mozilla)
  • element.webkitMatchesSelector( selector ) (webkit)
  • element.oMatchesSelector( selector ) (Opera)
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
  • 1
    written in 2022, it's a standard now with 96% support. https://caniuse.com/matchesselector – shtse8 Jun 19 '22 at 16:51
3

Additionally: a helper to use the MatchesSelector in major browsers

function matches() {
  var el = document.querySelector('body');
  return ( el.mozMatchesSelector || el.msMatchesSelector ||
           el.oMatchesSelector   || el.webkitMatchesSelector || 
           {name:'getAttribute'} ).name;
}
//=> usage
var someP = document.querySelector('p');
   ,rightClass = someP[matches()]('.someclass');

Still, /someclass/.test(someP.className) would be shorter here ;)

KooiInc
  • 119,216
  • 31
  • 141
  • 177
1

Generally, given element e, to check if it matches a selector you would use:

var check = false;
var c = e.parentNode.querySelectorAll('selector');
for(var i = 0; i < c.length; i++){
    if (c[i]==e){
        check = true;
    }
}

A more concise, but somewhat hacky solution is:

var c = e.parentNode.querySelectorAll('selector');
var check = Array.prototype.indexOf.call(c,e) != -1;

NOTE: check indicates whether or not the element matches the selector.

Here's a demo: http://jsfiddle.net/2vX3z/

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
  • The reason anyone would wish to check an element against a selector is because they found the element via some other means. In my case I'm building a function to find which of an elements parents, if any, match a particular selector. – mikemaccana Nov 15 '12 at 11:57
  • @nailer I've added a demo to my answer. – Asad Saeeduddin Nov 15 '12 at 12:05
1

Not in all browsers, but this might be helpful: http://caniuse.com/matchesselector

Example usage (from MDN page);

<div id="foo">This is the element!</div>
  <script type="text/javascript">
    var el = document.getElementById("foo");
    if (el.mozMatchesSelector("div")) {//or webkitMatchesSelector("div") in webkit browser or msMatchesSelector("div") in IE9/10
      alert("Match!");
    }
  </script>

Supose the only other way is to run querySelector and loop through all items testing if it is the same as one you already have.

Viktor S.
  • 12,736
  • 1
  • 27
  • 52
  • This looks like exactly what I want. MDN docs are at https://developer.mozilla.org/en-US/docs/DOM/Element.mozMatchesSelector . – mikemaccana Nov 15 '12 at 12:03
  • Race you to find the MDC docs? - sorry, I'm not sure I understand you correctly. Do you need MD**N** docs page? Link to it availale on a page I provided a link to – Viktor S. Nov 15 '12 at 12:05
  • MDN, ahem. I found the link myself. Edit: ah, so many great answers! – mikemaccana Nov 15 '12 at 12:08