Why is the childNodes count is greater than expected? - javascript

I have a question about DOM. Consider the following javascript code, the output will be 5.
<body>
<p>Hello</p>
<script>
function countBody() {
var childs = document.getElementsByTagName("body")[0].childNodes;
alert(childs.length);
}
window.onload = countBody;
</script>
</body>
Since I have two element nodes and two text nodes, what is the 5th node?

You have three text nodes.
Between the body start tag and the paragraph.
Between the paragraph and the script.
Between the script and the body end tag
… you could loop over childNodes and console.log() each value to see.

Just check it for yourself:
<body>
<p>Hello</p>
<script>
function countBody() {
var childs = document.getElementsByTagName("body")[0].childNodes;
console.log([].map.call(childs, function (node) { return node.textContent; }));
}
window.onload = countBody;
</script>
</body>
You have missed one text node in your counting. Please be aware that output from snippet will be different from code you have provided.

Related

How does Javascript filter out HTML tags while selecting words using regular expressions?

Notice:
I'm not parsing HTML with regex,
here I only use it for plain text.
It's just that it goes beyond plain text and affects other html tags
Why does everyone say I should use DOM instead of regular expressions?
DOM obviously cannot select all words on a web page based on an array of words.
before I used document.createTreeWalker() to filter all text labels, it was too complicated and caused more errors.
So I want to do it with simple regex instead. Do you have a better way?
I think just 'filter out all text inside "<>"' with very simple regex syntax wouldn't it work? Why make it so complicated?
I need to select the words from the page based on an array of words, and wrap the words around 'span' tags (keeping the original HTML tags).
The problem with my code is that it replaces the attribute values of the HTML tag as well.
I need regular expressions to filter out HTML tags and select words.
I added a condition to the regular expression :(^<.*>), but it didn't work and broke my code.
How to do?
My code:
code Error: The <div id="text"> should not be wrapped around the SPAN tag
<!DOCTYPE html>
<html>
<head>
<style>span{background:#ccc;}</style>
<script>
//wrap span tags for all words
function add_span(word_array, element_) {
for (let i = 0; i < word_array.length; i++) {
var reg_str = "([\\s.?,\"\';:!()\\[\\]{}<>\/])"; // + "^(<.*>)"
var reg = new RegExp(reg_str + "(" + word_array[i] + ")" + reg_str, 'g');
element_ = element_.replace(reg, '$1<span>$2</span>$3');
}
return element_;
}
window.onload = function(){
console.log(document.body.innerText);
// word array
var word_array = ['is', 'test', 'testis', 'istest', 'text']
var text_html = add_span(word_array, document.body.innerHTML);
document.body.innerHTML = text_html;
console.log(text_html);
}
</script>
</head>
<body>
<div id="text"><!--Error: The class attribute value here should not be wrapped around the SPAN tag-->
is test testis istest,
is[test]testis{istest}testis(istest)testis istest
</div>
</body></html>
I had fun with this one and learned a few things too. You could replace the traversal implementation with TreeWalker if you'd like. I added a nested div#text2 to demonstrate how it works with arbitrary tree depth. I tried to keep the same general approach you were using, but needed to make some modifications to the regex and add tree traversal. Hope this helps!
function traverse(tree) {
const queue = [tree];
while (queue.length) {
const node = queue.shift();
if (node.nodeType === Node.TEXT_NODE) {
const textContent = node.textContent.trim();
if (textContent) {
const textContentWithSpans = textContent
.replaceAll(/\b(is|test|testis|istest|text)\b/g, '<span>$&</span>');
const template = document.createElement('template');
template.innerHTML = textContentWithSpans;
const fragment = template.content;
node.parentNode.replaceChild(fragment, node);
}
}
for (let child of node.childNodes) {
queue.push(child);
}
}
}
traverse(document.getElementById('demo-wrapper'));
<div id="demo-wrapper">
<div id="text">
is test testis istest,
is[test]testis{istest}testis(istest)testis istest
<div id="text2">
foo bar test istest
</div>
</div>
</div>

How to built a text array of the document content with javascript

Hi how can I extract the text of an document as an array within javascript.
It´s easy to get the innerHTML, but I do not get the text before and after the div for example.
This should be the output:
[0]=before div
[1]=innerHTML
[2]=aferHTML
[3]=before div2
[4]=innerHTML2
[5]=aferHTML2
Of the following document:
<html><head>
<body>
before div <div>innerHTML </div>aferHTML
before div2 <div>innerHTML2 </div>aferHTML2
</body></html>
I found this link, but it does not get the text before and after the elements as well:
How to get all text from all tags in one array?
You scenario is not clear. Could you please elaborate more the specific reason.
However if you want to get text from all elements in a document, kindly review this thread -> link.
By using the childNodes property you can achieve this. But for afterHtml and before div2, you need to do some extra work because they are part of the same text node.
Please take a look at the snippet below. You can remove the last element of the array manually.
const arr = [];
document.body.childNodes.forEach(node => {
arr.push(node.textContent.trim());
})
console.log(arr)
<body>
before div <div>innerHTML </div>aferHTML
before div2 <div>innerHTML2 </div>aferHTML2
</body>
Okay here's mine.
As you can see, I wrapped your HTML inside a div with a class name content.
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div class="content">
before div <div>innerHTML </div>aferHTML
before div2 <div>innerHTML2 </div>aferHTML2
</div>
</body>
</html>
<script type="text/javascript">
var body = document.querySelector('.content').children;
var list = [];
for (var i = 0; i < body.length ; i++) {
var before = body[i].previousSibling.nodeValue.trim();
var inner = body[i].innerHTML;
var after = body[i].nextSibling.nodeValue.trim();
if (before && i == 0) list.push(before); //prevent duplication and empty value
list.push(inner);
if(after) list.push(after); //prevent empty value
}
console.log(list); //output
</script>
in innerHTML, you could split the string using inner.split(" ") if you like.

Find right line of code by Regex and replace text in it jQuery

I have two lines of javascript code at a Html body.
<script text="javascript">
Muse.Utils.initWidget('#widgetu94', ['#bp_infinity'], function(elem) { return new WebPro.Widget.Form(elem, {validationEvent:'submit',errorStateSensitivity:'high',fieldWrapperClass:'fld-grp',formSubmittedClass:'frm-sub-st',formErrorClass:'frm-subm-err-st',formDeliveredClass:'frm-subm-ok-st',notEmptyClass:'non-empty-st',focusClass:'focus-st',invalidClass:'fld-err-st',requiredClass:'fld-err-st',ajaxSubmit:true}); });/* #widgetu94 */
Muse.Utils.initWidget('#widgetu386', ['#bp_infinity'], function(elem) { return new WebPro.Widget.Form(elem, {validationEvent:'submit',errorStateSensitivity:'high',fieldWrapperClass:'fld-grp',formSubmittedClass:'frm-sub-st',formErrorClass:'frm-subm-err-st',formDeliveredClass:'frm-subm-ok-st',notEmptyClass:'non-empty-st',focusClass:'focus-st',invalidClass:'fld-err-st',requiredClass:'fld-err-st',ajaxSubmit:true}); });/* #widgetu386 */
</script>
I need to change text ajaxSubmit:true to ajaxSubmit:false only for the second line Muse.Utils.initWidget('#widgetu386'...
I've tried to use this code
<script>
document.body.innerHTML = document.body.innerHTML.replace('ajaxSubmit:true', 'ajaxSubmit:false');
</script>
But after that all of ajaxSubmitare gonna to false.
Maybe I need more Regural Expression?
<script>
document.body.innerHTML = document.body.innerHTML.replace(/MagicRegExp/, 'ajaxSubmit:false');
</script>
I just want find it by '#widgetu386'
Please help me. I don't know what to do.
You use the id of an element to make changes to that specific element. I have never used Muse.Utils.initWidget() personally, but I am assuming that the first paramter of the function is the element id.
<script>
document.getElementById("#widgetu386").innerHTML =
document.getElementById("#widgetu386").innerHTML.replace(
'ajaxSubmit:true',
'ajaxSubmit:false'
);
</script>

Changing content of class using Javascript

I started reading JavaScript in W3schools and testing out/changing few things in the examples they give so I can see what is doing what but didn't manage to identify the syntax, yet.
Below is the original code to change p tag content, the link to it.
<p id="demo">
JavaScript can change the content of an HTML element.
</p>
<script>
function myFunction()
{
x = document.getElementById("demo"); // Find the element
x.innerHTML = "Hello JavaScript!"; // Change the content
}
</script>
<button type="button" onclick="myFunction()">Click Me!</button>
I want to know how to change contents with the same class, but failed as you can see that the example below doesn't work. Fiddle of code below.
<p class="demo">
JavaScript can change the content of an HTML element.
</p>
<p class="demo">Yolo</p>
<script>
function myFunction()
{
x = document.getElementsByClassName("demo"); // Find the element
x.innerHTML = "Hello JavaScript!"; // Change the content
}
</script>
<button type="button" onclick="myFunction()">Click Me!</button>
If you could show me how ^^" and help me understand, is "getElementById" a variable that could be anything else or is it a command?
Your x - is array of elements. try to use loop:
<body>
<p class="demo">JavaScript can change the content of an HTML element.</p>
<p class="demo">Yolo</p>
<button type="button" onclick="myFunction()">Click Me!</button>
<script>
function myFunction()
{
x=document.getElementsByClassName("demo"); // Find the elements
for(var i = 0; i < x.length; i++){
x[i].innerText="Hello JavaScript!"; // Change the content
}
}
</script>
</body>
See FIDDLE
Notice how when you use:
x=document.getElementsByClassName("demo");
It is Elements instead of Element. This is because it returns an array a HTMLCollection of all the elements with one particular class name. In order to combat this, you can choose the first element in the array:
x=document.getElementsByClassName("demo")[0];
It is easier to use jQuery with Javascript
See this example:
http://jsfiddle.net/37jq9/3/
If you use jquery instead of calling
x=document.getElementsByClassName("demo");
you can use
x = $('.demo');
but you can just call the function like this:
$(document).ready(function(){
$('button').click(function(){
$('.demo').text('Hello Javascript');
})
})

JS get value of generated textnode

I have this Javascript in a for loop:
renderAElements[i] = document.createElement ("a");
renderAElements[i].setAttribute("href", "#");
renderAElements[i].setAttribute("class", "expander");
renderAElements[i].appendChild(expand);
alert (renderAElements[i].nodeValue);
where expand is created as:
var expand = document.createTextNode("+");
The alert, which is meant to return the link text of each created element returns null. Why is this?
Because you are trying to get the nodeValue of the Element node and not the Text node.
alert (renderAElements[i].firstChild.nodeValue);
It's because the a element contains another element and not a value. If you want to get the text out of the node you'll need to do either
renderAElements.childNodes[0].nodeValue
or
renderAElements.innerText
Check this out
<head>
<script type="text/javascript">
function GetTextNode () {
var textContainer = document.getElementById ("textContainer");
var textNode = textContainer.firstChild;
alert (textNode.data);
}
</script>
</head>
<body>
<div id="textContainer">This is a simple text in the container.</div>
<button onclick="GetTextNode ()">Get the contents of the container</button>
</body>
try this alert (renderAElements[i].firstChild.nodeValue);

Categories