3

There is the site : http://youmightnotneedjquery.com/ : and with my AngularJS application, I would really like to remove jQuery. The reason I still need jQuery and I can't just use jQLite that AngularJS comes with is because jQLite does not support selectors based on classes.

The issue with querySelectorAll() is that when I try to run this:

el.querySelectorAll('> .content')

I get this:

SyntaxError: Failed to execute query: '> span' is not a valid selector.

Is there a way to write this selector with just native DOM methods?

ryanzec
  • 27,284
  • 38
  • 112
  • 169
  • 2
    On the other hand, you might need jQuery. It is fundamentally a DOM manipulation engine, with really nice AJAX capabilities on top, and a really powerful CSS selector engine underneath. My favorite part of that website is that 80% of the examples replace 1 line of jQuery with 5-6 lines of JavaScript. Is removing a library worth the code bloat? In my opinion, maintainable code is exponentially better than independent code. – rockerest Jan 31 '14 at 17:57
  • 1
    You can always just include a robust selector engine such as `qwery`, `Sizzle` or `Slick` – megawac Jan 31 '14 at 18:31
  • @ryanzec: check my answer out, it would help you to meet your needs without using jQuery. – Mehran Hatami Jan 31 '14 at 19:54

3 Answers3

1

If you are really forced to use jQuery to find the .content first level childs, use XPath instead, it will do the exact same thing:

var xpathQuery = "./*[@class='content'";
xpathQuery += " or starts-with(@class,'content ')";
xpathQuery += " or contains(@class,' content ')";
xpathQuery += " or substring(@class, string-length(@class)-6)=' content']";
var iterator=document.evaluate(xpathQuery , el, null, XPathResult.ANY_TYPE, null );
var contentNode = iterator.iterateNext();

just be careful using ./ instead of .// is something like using '>' instead of space ' ' in jQuery selectors.

I managed to create a general function for your use:

function findByClassName(el, className, firstLevel) {
    var xpathQuery = firstLevel ? "./" : ".//";
    xpathQuery += "*[@class='" + className + "'";
    xpathQuery += " or starts-with(@class,'" + className + " ')";
    xpathQuery += " or contains(@class,' " + className + " ')";
    xpathQuery += " or substring(@class, string-length(@class)-" + (className.length) + ")=' " + className + "']";

    var iterator = document.evaluate(xpathQuery, el, null, XPathResult.ANY_TYPE, null);
    var nodes = [];
    var node;
    while (node = iterator.iterateNext()) {
        nodes.push(node);
    }
    return nodes;
}

for your use case you should use it like:

var contentNodes = findByClassName(el, 'content', true);

and this is the working jsfiddle DEMO.

Mehran Hatami
  • 12,723
  • 6
  • 28
  • 35
0

If you want only direct children of el that have the class .content, then you can use this:

function queryChildren(el, sel) {
    var all = el.querySelectorAll(sel);
    var filtered = [];
    for (var i = 0; i < all.length; i++) {
        if (all[i].parentNode == el) {
            filtered.push(all[i]);
        }
    }  
    return filtered;
}

queryChildren(el, ".content");

This runs the query that finds all descendants that match the class name and then filters that list to only the ones who are direct children of the passed in element.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
-1

You need a parent in order to have a child. Maybe something like this ?

el.querySelectorAll('body > .content')
Yves Lange
  • 3,914
  • 3
  • 21
  • 33
  • 1
    If you apply `querySelectorAll` to a specific element, shouldn't it be searching for that element's children, not children of `body`? – Barmar Jan 31 '14 at 17:56
  • @Barmar yea, I would expect it to find the direct child of the el DOM element. – ryanzec Jan 31 '14 at 17:57
  • Then you should read this: http://stackoverflow.com/questions/3680876/use-queryselectorall-to-retrieve-direct-children – Yves Lange Jan 31 '14 at 18:07