I want to get all the descendent text nodes of an element as a jQuery collection. What's the best way?
#1 building
You can also do this:
var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){ return this.nodeType == 3; });
The above code filters textNodes from the direct child nodes of a given element.
#2 building
For me, normal old-fashioned. contents() seems to return text nodes, just be careful with selectors so you know they will be text nodes.
For example, this wraps all the text content of TD in my table with the pre tag, no problem.
jQuery("#resultTable td").content().wrap("<pre/>")
#3 building
jQuery.contents() May and jQuery.filter Use together to find all child text nodes. With a few changes, you can find the grandchildren text node. No recursion required:
$(function() { var $textNodes = $("#test, #test *").contents().filter(function() { return this.nodeType === Node.TEXT_NODE; }); /* * for testing */ $textNodes.each(function() { console.log(this); }); }); div { margin-left: 1em; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div id="test"> child text 1<br> child text 2 <div> grandchild text 1 <div>grand-grandchild text 1</div> grandchild text 2 </div> child text 3<br> child text 4 </div>#4 building
For some reason, contents() doesn't work for me, so if it doesn't work for you, it's a solution I've made, and I created jQuery.fn.descendants to choose whether to include text nodes or not
usage
Get all descendants, including text and element nodes
jQuery('body').descendants('all');
Get the descendants of all text only nodes
jQuery('body').descendants(true);
Get all the descendants of the returned element nodes only
jQuery('body').descendants();
Coffee script Original:
jQuery.fn.descendants = ( textNodes ) -> # if textNodes is 'all' then textNodes and elementNodes are allowed # if textNodes if true then only textNodes will be returned # if textNodes is not provided as an argument then only element nodes # will be returned allowedTypes = if textNodes is 'all' then [1,3] else if textNodes then [3] else [1] # nodes we find nodes = [] dig = (node) -> # loop through children for child in node.childNodes # push child to collection if has allowed type nodes.push(child) if child.nodeType in allowedTypes # dig through child if has children dig child if child.childNodes.length # loop and dig through nodes in the current # jQuery object dig node for node in this # wrap with jQuery return jQuery(nodes)
Insert Javascript version
var __indexOf=[].indexOf||function(e)return-1}; /* indexOf polyfill ends here*/ jQuery.fn.descendants=function(e)if(r.childNodes.length)else}return f};for(s=0,o=this.length;s<o;s++)return jQuery(i)}
Unsized Javascript version: http : //pastebin.com/cX3jMfuD
This is a cross browser, with a small Array.indexOf in the code.
#5 building
I got a lot of blank text nodes with acceptable filter capabilities. If you are only interested in selecting text nodes that contain non spaces, try adding the nodeValue of the conditional condition to the filter function, such as the simple $. trim(this.nodevalue)! = = '':
$('element') .contents() .filter(function(){ return this.nodeType === 3 && $.trim(this.nodeValue) !== ''; });
Or, to avoid strange situations where the content looks blank but is not blank (for example, soft hyphen & shy; characters, line breaks \ \ n, tabs, etc.), you can try using regular expressions. For example, \ \ S will match any non white space characters:
$('element') .contents() .filter(function(){ return this.nodeType === 3 && /\S/.test(this.nodeValue); });