<div class="title">
I am text node
<a class="edit">Edit</a>
</div>
I wish to get the "I am text node", do not wish to remove the "edit" tag, and need a cross browser solution.
<div class="title">
I am text node
<a class="edit">Edit</a>
</div>
I wish to get the "I am text node", do not wish to remove the "edit" tag, and need a cross browser solution.
You can also use XPath's
text()
node test to get the text nodes only. For exampleYou can get the nodeValue of the first childNode using
http://jsfiddle.net/TU4FB/
.text() - for jquery
Pure JavaScript: Minimalist
First off, always keep this in mind when looking for text in the DOM.
MDN - Whitespace in the DOM
This issue will make you pay attention to the structure of your XML / HTML.
In this pure JavaScript example, I account for the possibility of multiple text nodes that could be interleaved with other kinds of nodes. However, initially, I do not pass judgment on whitespace, leaving that filtering task to other code.
In this version, I pass a
NodeList
in from calling / client code.Of course, by testing
node.hasChildNodes()
first, there would be no need to use a pre-test loop.Pure JavaScript: Robust
Here the function
getTextById()
uses two helper functions:getStringsFromChildren()
andfilterWhitespaceLines()
.getStringsFromChildren()
filterWhitespaceLines()
getTextById()
Next, the return value (Array, or null) is sent to the client code where it should be handled. Hopefully, the array should have string elements of real text, not lines of whitespace.
Empty strings (
""
) are not returned because you need a text node to properly indicate the presence of valid text. Returning (""
) may give the false impression that a text node exists, leading someone to assume that they can alter the text by changing the value of.nodeValue
. This is false, because a text node does not exist in the case of an empty string.Example 1:
Example 2:
The problem comes in when you want to make your HTML easy to read by spacing it out. Now, even though there is no human readable valid text, there are still text nodes with newline (
"\n"
) characters in their.nodeValue
properties.Humans see examples one and two as functionally equivalent--empty elements waiting to be filled. The DOM is different than human reasoning. This is why the
getStringsFromChildren()
function must determine if text nodes exist and gather the.nodeValue
values into an array.In example two, two text nodes do exist and
getStringFromChildren()
will return the.nodeValue
of both of them ("\n"
). However,filterWhitespaceLines()
uses a regular expression to filter out lines of pure whitespace characters.Is returning
null
instead of newline ("\n"
) characters a form of lying to the client / calling code? In human terms, no. In DOM terms, yes. However, the issue here is getting text, not editing it. There is no human text to return to the calling code.One can never know how many newline characters might appear in someone's HTML. Creating a counter that looks for the "second" newline character is unreliable. It might not exist.
Of course, further down the line, the issue of editing text in an empty
<p></p>
element with extra whitespace (example 2) might mean destroying (maybe, skipping) all but one text node between a paragraph's tags to ensure the element contains precisely what it is supposed to display.Regardless, except for cases where you are doing something extraordinary, you will need a way to determine which text node's
.nodeValue
property has the true, human readable text that you want to edit.filterWhitespaceLines
gets us half way there.At this point you may have output that looks like this:
There is no guarantee that these two strings are adjacent to each other in the DOM, so joining them with
.join()
might make an unnatural composite. Instead, in the code that callsgetTextById()
, you need to chose which string you want to work with.Test the output.
One could add
.trim()
inside ofgetStringsFromChildren()
to get rid of leading and trailing whitespace (or to turn a bunch of spaces into a zero length string (""
), but how can you know a priori what every application may need to have happen to the text (string) once it is found? You don't, so leave that to a specific implementation, and letgetStringsFromChildren()
be generic.There may be times when this level of specificity (the
target
and such) is not required. That is great. Use a simple solution in those cases. However, a generalized algorithm enables you to accommodate simple and complex situations.This will ignore the whitespace as well so, your never got the Blank textNodes..code using core Javascript.
Check it on jsfiddle : - http://jsfiddle.net/webx/ZhLep/
This gets the
contents
of the selected element, and applies a filter function to it. The filter function returns only text nodes (i.e. those nodes withnodeType == Node.TEXT_NODE
).