I want to get the textContent of the current node but not of any of the descendant nodes. Any ideas as to how I might do that?
textContent does the later. nodeValue returns an empty string.
Not sure if there is an easier way, but you can always iterate over all node's children and get value of text nodes.
var text = "";
var child = element.firstChild;
while(child) {
if (child.nodeType === 3) { // nodeType === Node.TEXT_NODE
text += child.nodeValue;
}
child = child.nextSibling;
}
console.log(text);
http://jsfiddle.net/zqbyE/
I had the same issue and solved it by getting the textContent of the first child, which actually is the text. The code therefore becomes :
node.firstChild.textContent
I just created a span within the current node that contains that node's specific textContent and am getting the txt for that. I dunno... seems easier than going over all the node's children. Thanks for the suggestion though!
Related
I'm writing a Chrome content script extension and I need to be able to target a specific element that, unfortunately, has no unique identifiers except its parent element.
I need to target the immediate first child element of parentElement. console.log(parentElement) reports both of the child elements/nodes perfectly, but the succeeding console logs (the ones that target the childNodes) always return an undefined value no matter what I do.
This is my code so far
(I have excluded the actual names to avoid confusion and extra, unnecessary explanation)
function injectCode() {
var parentElement = document.getElementsByClassName("uniqueClassName");
if (parentElement && parentElement.innerHTML != "") {
console.log(parentElement);
console.log(parentElement.firstElementChild);
console.log(parentElement.firstChild);
console.log(parentElement.childNodes);
console.log(parentElement.childNodes[0]);
console.log(parentElement.childNodes[1]);
} else {
setTimeout(injectCode, 250);
}
}
How do I select the first child element/node of parentElement?
Update:
parentElement.children[0] also has the same error as parentElement.childNodes[0].
Both these will give you the first child node:
console.log(parentElement.firstChild); // or
console.log(parentElement.childNodes[0]);
If you need the first child that is an element node then use:
console.log(parentElement.children[0]);
Edit
Ah, I see your problem now; parentElement is an array.
If you know that getElementsByClassName will only return one result, which it seems you do, you should use [0] to dearray (yes, I made that word up) the element:
var parentElement = document.getElementsByClassName("uniqueClassName")[0];
Hello all you ridiculously genius people!
So I'm creating a basic word processor, and I need to have an option to clear formatting in a certain section. The place the user is typing is split up into several different divs, and whenever they hit enter it starts a new div. When they add a style option (Bold, italics, etc.) it ads the correct html tag.
Well, I want the user to be able to clear all formatting on text they highlight. To do this, I need to find the element that all of them share. so if it displayed "Here is my text" in a structure like this:
<div id="1">
<div>Here</div>
<div>is</div>
<div>some</div>
<div>text</div>
</div>
and the user highlighted all 4 words, I would need to computer to give me the div with the id "1" because that is what they all share in common.
I am completely stumped on this, and have absolutely no clue where to start, so I really don't have any code for you. I will be using window.getSelected(); to get the actual text, but I have no idea how to go about finding the divs around it.
Thanks for your help!
If you are using window.getSelection(), it returns a selection object which contains properties .anchorNode and .focusNode which are the nodes at the start and end of the selection. You can then use those nodes to walk up the parent chain to find any level of parent you want.
The closest common parent could be found by getting the immediate parent of the first object and then seeing if it is also a parent of the second object. If not, go up one parent higher until you eventually find a common parent.
function findCommonParentElement(startNode, endNode) {
// see if node has a particular parent
// by walking up the parent chain and comparing parents
function hasParent(node, parent) {
while (node && node !== parent && node !== document.body) {
node = node.parentNode;
}
return node === parent;
}
// for text nodes, get the containing element
// for elements, just return what was passed in
function getElement(node) {
while (node && node.nodeType !== 1) {
node = node.parentNode;
}
return node;
}
// go up the parent chain of endNode looking for a node
// that startNode has as a parent
while (endNode && !hasParent(startNode, endNode)) {
endNode = endNode.parentNode;
}
// return the containing element - so it won't return a textnode
return getElement(endNode);
}
// Usage:
var sel = window.getSelection();
var commonParent = findCommonParentElement(sel.anchorNode, sel.focusNode);
Working demo: http://jsfiddle.net/jfriend00/GV96w/
function countChars(elm) {
if (elm.nodeType == 3) { // TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += countChars(child);
}
return count;
}
I tried passing this function a string like countChars("hello"); but that didn't work. What are examples of elements that I can pass?
It expects a reference to a DOM node. That could be a text node (nodeType == 3) or an element node (nodeType == 1) by the look of the function. For example:
countChars(document.getElementById("someId"));
The following HTML would cause the above call to return 5:
<span id="someId">Hello</span>
If the argument is a text node the function returns the number of characters that make up that node. If the argument is an element node the function recursively counts the number of characters that make up the descendant text nodes of the element.
The following HTML would cause the above call to return 10 (the child node is included):
<div id="someId">Outer<span>inner</span></div>
You can see the full list of node types on MDN.
It expects DOM nodes, like something you'd get from document.getElementById() or the list of child nodes on another DOM node.
What it does is find all the text nodes in the list of child nodes of an element and count up how many characters they contain. It does it recursively, so it will find all the text within a container, no matter how far separated in the element graph.
Also it should be noted that this code expects a node to be either a text node or else an element. There are other types of nodes, however, most notably comment nodes.
Looks like you should pass a dom element.
An element (node, actually, hence why it checks if nodeType is a text node), e.g.:
countChars(document.getElementById("myid"));
You can get nodeType over a DOM fragment, so... you must enter a DOM element as input
https://developer.mozilla.org/en/nodeType
The example from that link shows it
var node = document.documentElement.firstChild;
if(node.nodeType != Node.COMMENT_NODE)
alert("You should comment your code well!");
How can I get the second child node of a tr, which has 3 td in it?
I have a code
rows=document.getElementById('mytr');
rows.firstChild.innerHTML='ddsds';
rows.lastChild.innerHTML='dd';
Now I would like to change the content in the middile also. how can I do that?
rows.secondChild.innerHTML='ddsds';
will not work.
Although I'd recommend using something like jQuery for this kind of manipulation, this is what you want:
var rows = document.getElementById('mytr');
var cells = table.getElementsByTagName('td');
cells[0].innerHTML = 'ddsds';
cells[1].innerHTML = 'ddsds';
cells[2].innerHTML = 'dd';
Access the childNodes or cells as array
rows.childNodes[1].innerHTML would do the second cell, as would
rows.cells[1].innerHTML
you can also use nextSibling,
rows.firstChild.nextSibling.innerHTML='ddsds';
and be careful while accessing child, these can return a text node if there are some white spaces. always try to validate if the child is not a text node using
rows.firstChild.nodeType == 1 // this will check if the node is not a text node
You can use .childNodes to find childnode by it's index.
rows.childNodes[1].innerHTML = 'foo'; // set foo to second child
if (rows.childNodes.length > 0)
rows.childNodes[1].innerHTML = "ddsds";
Is there a handy way to "touch" a DOM element? I'd like to remove the element and insert it again at the same position. Something like this:
element.parentNode.removeChild(element).appendChild(element);
except that appendChild inserts the element as the last sibling.
Use insertBefore instead of appendChild.
var other = element.nextSibling;
if ( other ) {
other.parentNode.removeChild(element);
other.parentNode.insertBefore(element,other);
} else {
other = element.parentNode;
other.removeChild(element);
other.appendChild(element);
}
This creates a dummy text node to be used as a marker and replaces it with the node. Later when the node is to be re-inserted, replace it with the dummy node so the position is preserved.
Node.replaceChild
var dummy = document.createTextNode('');
var parent = element.parentNode;
parent.replaceChild(dummy, element); // replace with empty text node
parent.replaceChild(element, dummy); // swap out empty text node for original
Yes but it would be better to use the DOM cloneNode(true) as it would retain all of the child nodes and properties:
// Copy the node.
var theOldChild = document.getElementById("theParent").childNodes[blah]
var theNewChild = theOldChild.cloneNode(true);
// Find the next Sibling
var nextSib = theOldChild.nextSibling();
// Remove the old Node
theOldChild.parentNode.removeChild(theOldChild)
// Append where it was.
nextSib.parentNode.inserertBefore(theNewChild, nextSib);
That is the way that I would do it as you can hold onto the variable "theNewChild" 100% as it was and insert it back into the document at any time.