I have the following HTML string:
<div><p>Hello <b>how are</b> you?</div>
I would like to loop the HTML string DOM and wrap each word with a span tag and the word number as id so result will be like this:
<div><p><span id="word-1">Hello</span> <b><span id="word-2">how</span> <span id="word-3">are</span></b> <span id="word-4">you?</span></div>
I've tried to use the JQuery method $.parseHTML but no luck to count the words because DOM node value can contain more than one word in it..
In addition, if inside the word there is inline tags such <b> / <i> so from DOM point of view each tag has a different node value even when its the same word)
Any idea how to solve this issue? how to count words inside a HTML DOM string?
Thanks
Try this.
HTML
<div id="content">
<div><p>Hello <b>how are</b> you?</div>
</div>
Script
var textNodes = $("#content *").contents().filter(function() {
return this.nodeType === 3;
});
var counter = 1;
for(var i = 0;i<textNodes.length;i++)
{
var val = $(textNodes).eq(i).text();
var words = val.split(" ");
var final = "";
for(var j = 0;j<words.length;j++)
{
if(words[j].trim() != "")
{
final += "<span id='"+ counter +"'>"+ words[j] +" </span>";
counter++;
}
}
$($(textNodes)[i]).replaceWith(final);
}
Jsfiddle Link
As of my understanding of your question this should work.
var allText = $("body").text().replace(/<[^>]*>/g, "");
var words = allText.split(' ');
for(var i=0;i<words.length;i++)
{
$(div).append("<span id = 'word-'"+i+">"+words[i]+"</span>")
}
Related
I have a div in which I render through javascript inputs and text dynamically. I am trying to capture the text of this div (both input values and text).
My first step if to capture the parent div:
let answerWrapper = document.getElementById("typing-answer-wrapper");
The issue now is that using the innerHTML will give me the whole html string with the given tags and using the inerText will give me the text, excluding the tags.
In the following case scenario:
the console inspect is:
What is the way to capture: $2.4 if the inputs have 2 and 4
and $null.null if the inputs are blank.
Any help is welcome
You could iterate over all of the element's child nodes and concatenate their wholeText or value else 'null'. For inputs the wholeText will be undefined. If they have no value we'll return 'null'. Be aware that spaces and line-breaks will also be included so you may want to strip these later (or skip them in the loop) but as a proof of concept see the following example:
var typingAnswerWrapper = document.getElementById("typing-answer-wrapper");
function getVal(){
var nodeList = typingAnswerWrapper.childNodes;
var str = "";
for (var i = 0; i < nodeList.length; i++) {
var item = nodeList[i];
str+=(item.wholeText || item.value || "null");
}
console.log(str);
}
getVal();
//added a delegated change event for demo purposes:
typingAnswerWrapper.addEventListener('change', function(e){
if(e.target.matches("input")){
getVal();
}
});
<div id="typing-answer-wrapper">$<input type="number" value=""/>.<input type="number" value="" />
</div>
Here's how you could do it :
function getValue() {
var parent = document.getElementsByClassName('typing-answer-wrapper')[0],
text = [];
const children = [...parent.getElementsByTagName('input')];
children.forEach((child) => {
if (child.value == '')
text.push("null")
else
text.push(child.value)
});
if (text[0] != "null" && text[1] == "null") text[1] = "00";
document.getElementById('value').innerHTML = "$" + text[0] + "." + text[1]
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<div class="typing-answer-wrapper">
$
<input type="number"> .
<input type="number">
</div>
<button onclick="getValue()">get value</button>
<div id="value"></div>
You can fetch input feild values by their respective ids $('#input_feild_1').val() will give the first feild value and similarly $('#input_feild_2').val() for second feild and contruct use them to construct whatever as u wish. As in your case this should work
value_1 = $('#input_feild_1_id').val()
value_2 = $('#input_feild_2_id').val()
you need something like "$ + value_1 + . + value_2"
Using a for loop in javascript to create multiple html div's.
for(var i = 0; i < lines.length; i++){
document.getElementById("rotate").innerHTML+="<div><div><a href='' id='idWithIndex_i'>";
document.getElementById("idWithIndex_i").innerHTML+=lines[i];
document.getElementById("rotate").innerHTML+="</a></div></div>";
}
The html should look like this for index 0:
<div>
<div>
<a href='' id='idWithIndex_0'>
line1
</a>
</div>
</div>
I want to define the index in the id of the anchor. How can I change the javascript? Thanks.
The problem is in this line:
for(var i = 0; i < lines.lenght; i++){
lenght does not exists in javascript. Use length instead.
Also, for concatenation, use this:
document.getElementById("rotate").innerHTML+='<div><div><a href="" id="idWithIndex_'+i+'">';
or using string templates from ES6 in order to obtain a cleaner solution.
document.getElementById("rotate").innerHTML+=`<div><div><a href="" id="idWithIndex_${i}">`;
Right now your i is just a part of a string, here's what you want:
for(var i = 0; i < lines.length; i++){
document.getElementById("rotate").innerHTML+="<div><div><a href='' id='idWithIndex_" + i + ">";
document.getElementById("idWithIndex_" + i).innerHTML+=lines[i];
document.getElementById("rotate").innerHTML+="</a></div></div>";
}
id='idWithIndex_"+i+"'
You need to break out of the string and then concatenate with + the variable.
In steps:
"idWithIndex_" is the first part of your fixed string
with + you append something to the former part
we append the variable i
after the variable we append the rest of the fixed string using another +.
Also type in your for loop: length instead of lenght
There is a way nicer way to do this:
var counter = 0;
//method 1 - createElement
document.querySelector("#add_method1").addEventListener("click", function(){
//add a click event to the add button
var node = document.createElement("div"); //create a new element
var innernode = document.createElement("div"); //create second node
var linknode = document.createElement("a");
linknode.setAttribute("href", '');
linknode.setAttribute("id", "idWithIndex_" + counter) //set id
linknode.innerHTML += "test"+counter; //lines[i] in your code;
counter++;
//time to append
innernode.appendChild(linknode);
node.appendChild(innernode);
document.getElementById("rotate").appendChild(node);
},true);
//method 2 - cloneNode
document.querySelector("#add_method2").addEventListener("click", function(){
//add a click event to the add button
var cloned = document.querySelector(".copynode").cloneNode(true); //true for deep cloning
cloned.removeAttribute("class"); //remove class
var a = cloned.querySelector("div > a"); //select link
a.setAttribute("id", "idWithIndex_" + counter) //set id
a.innerHTML += "test"+counter; //lines[i] in your code;
counter++;
//time to append
document.getElementById("rotate").appendChild(cloned);
},true);
/*css for method 2 */
.hidden {
display: hidden;
}
<div id="rotate"></div>
<button id="add_method1">add using document.createElement</button>
<button id="add_method2">add using element.cloneNode</button>
<!-- html for method 2 -->
<div class="copynode hidden">
<div>
</div>
</div>
for(var i = 0; i < lines.length; i++){
document.getElementById("rotate").innerHTML+="<div><div><a href='' id='idWithIndex_"+i+"'>";
document.getElementById("idWithIndex_"+i).innerHTML+=lines[i];
document.getElementById("rotate").innerHTML+="</a></div></div>";
}
First off, you have a type at .lenght.
Also, The "i" is not a part of the string, its a variable, so you need to add the value of i as the id od the div, not the string "i".
Try this
for(var i = 0; i < lines.lenght; i++){
document.getElementById("rotate").innerHTML+="<div><div><a href='' id='idWithIndex_"+i+"'>";var id = "idWithIndex_"+i;
document.getElementById(id).innerHTML+=lines[i];
document.getElementById("rotate").innerHTML+="</a></div></div>";
}
var lines = [1,2,3,4]
var i;
for(i = 0; i < lines.length; i++){
document.getElementById("rotate").innerHTML+="<div><div><a href='' id='idWithIndex_"+i+"'> " + lines[i]+"</a></div></div>";
}
<div id="rotate">Hi</div>
As others have mentioned you need to either concatenate the values into the string or use a template string to inject them into the string.
I wanted to suggest a little refactoring. DOM access is relatively expensive, with 3 getElementById queries and 3 changes to the DOM via innerHTML per loop, that creates a lot of unnecessary overhead. In most cases it probably doesn't matter, but if there were a lot of items in lines, it could bring the browser to its knees. It would be better to build a string of the HTML you are injecting and just inject once:
let lines = ['a', 'b', 'c'];
let linesHtml = ''; // buffer for the HTML we are building
for(let i = 0; i < lines.length; i++) {
// there is no need to create the link and then inject content into it,
// we can just inject the content right into the element in the HTML
linesHtml += `<div>
<div>
<a href='' id='idWithIndex_${i}'>
${lines[i]}
</a>
</div>
</div>`;
}
// now that we know what we are injecting, make a single DOM update
document.getElementById("rotate").innerHTML += linesHtml;
div {
border: 1px solid #000;
padding: 3px;
}
<div id="rotate"></div>
I used a template literal instead of a normal string because it allows you to easily create multi-line strings, for easily readable embedded HTML. This can help a lot with the maintainability of your code. Any recent browser supports them (IE isn't recent; if you have to support it, you have my condolences).
I want to insert </div><div id = '2'> to my html page
This is current code:
<body>
<div id='1'>
<p>abc1</p>
<p>abc2</p>
</div>
</body>
This is code I want to be after insert:
<body>
<div id='1'>
<p>abc1</p>
</div>
<div id='2'>
<p>abc2</p>
</div>
</body>
My javascript code is
var bodyTag = document.getElementsByTagName("body")[0];
var divTag = bodyTag.getElementsByTagName("div")[0];
var pCount = divTag.getElementsByTagName("p").length;
var str = '</div><div id = "2">';
var insert_pos = 1;
for(var i = 0 ; i < pCount; i++)
{
if(i != insert_pos)
{
s += '<p>'+ divTag .getElementsByTagName("p")[i].innerHTML + '</p>';
}
else
{
s += '<p>'+ divTag .getElementsByTagName("p")[i].innerHTML + '</p>';
s += str;
}
}
I used javascript to insert with method innerHTML but it inserts only <div id = '2'>, </div> is not inserted.
Please help me! Thank you very much!
Try this : You can make use of .after() and .append() as shown below
$(function(){
//add div2 after div1
$('#1').after('<div id="2"></div>');
//append last p to div2
$('#2').append($('#1 p:last'));
});
JSFiddle Demo
var bodyTag = document.getElementsByTagName("body")[0];
var divTag = bodyTag.getElementsByTagName("div")[0];
var pCount = divTag.getElementsByTagName("p").length;
var str = '<div>';
var insert_pos = 1;
for(var i = 0 ; i < pCount; i++)
{
if(i == insert_pos)
{
str += '<p>'+ divTag .getElementsByTagName("p")[i].innerHTML + '</p>';
}
}
str+='</div>';
bodyTag.innerHTML+=str;
<body>
<div id='1'>
<p>abc1</p>
<p>abc2</p>
</div>
</body>
I think this could fulfill.
var pEls = document.getElementsByTagName('p'),
parentDivEl = document.getElementById('1'),
targetPEl = parentDivEl.removeChild(pEls[1]);
var divEl = document.createElement('div');
divEl.id = "2";
divEl.appendChild(targetPEl);
parentDivEl.parentNode.insertBefore(divEl, parentDivEl.nextSibling);
<body>
<div id='1'>
<p>abc1</p>
<p>abc2</p>
</div>
</body>
Using Javascript, here you go...
var pEls = document.getElementsByTagName('p'),
parentDivEl = document.getElementById('1'),
targetPEl = parentDivEl.removeChild(pEls[1]);
var divEl = document.createElement('div');
divEl.id = "2";
divEl.appendChild(targetPEl);
parentDivEl.parentNode.insertBefore(divEl, parentDivEl.nextSibling);
This one is interesting. I originally tried to use the insertAdjacentHTML function to insert the string '</div><div id="2">' after the first <p>, but strangely, the Dom rearranges these divs automatically to be '<div id="2"></div>'.
So, the next best option is to just do it manually. I'm not sure if this will work in your case, but it does output the desired result with less javascript.
Check out this fiddle.
http://jsfiddle.net/justinbchristensen/k2y2uggj/
var div1 = document.getElementById('1');
var ps = div1.children;
div1.removeChild(ps[1]);
div1.insertAdjacentHTML('afterend','<div id="2"><p>abc2</p></div>');
1) Get the div by its ID, assign it to a variable 'div1'
2) Access the 2 child <p> of the div and assign them to 'ps'
3) Remove the second <p>
4) Insert the entire second <div> with its child <p>
Let me know if this will work for your situation. If not, I'm sure we can come up with something more creative.
Thank you very much. I want to save the process time so I find the way to insert code like that. But it seems no way to insert. So, the right way to do is Moving the childs in this div to another. Thanks for your solution :)
Please have a look to this DOM Tree...
<div>
<div>
<span> Home1 </span>
</div>
<span> Home2 </span>
<span> Home3 </span>
</div>
Now suppose I have a scenario where somehow I got the innerHTML of first span Home1.
Is it possible to get the element span and its parent div by using only this (Home1) information.
Here is what you want.
Here is html:
<label>opal fruits</label>
Here is jQuery:
$("label:contains(opal fruits)")
var mySpans = document.getElementsByTagName(span);
for(var i=0;i<mySpans.length;i++){
if(mySpans[i].innerHTML == 'Home1'){
var parent = mySpans[i].parentNode;
break;
}
}
this selects the parent of span having innerHTML Home1
There are so many ways to get info about your elements.
Using the innerHTML as an identifier is not a good solution.
You probably need some sort of event to that makes you search for that "Menu1"
So here is a click handler that works also on other events that give you information about what you have clicked.
function handler(e){
var txt='You clicked on a '+e.target.nodeName+'\n';
txt+='The innerHTML is '+e.target.innerHTML+'\n';
txt+='The text is '+e.target.textContent+'\n';
txt+='The parentNode is '+e.target.parentNode.nodeName+'\n';
alert(txt)
}
document.addEventListener('click',handler,false)
DEMO
function handler(e) {
var txt = 'You clicked on a ' + e.target.nodeName + '\n';
txt += 'The innerHTML is ' + e.target.innerHTML + '\n';
txt += 'The text is ' + e.target.textContent + '\n';
txt += 'The parentNode is ' + e.target.parentNode.nodeName + '\n';
alert(txt)
}
document.addEventListener('click', handler, false)
<div>
<div><span>Menu1</span></div><span>Menu2</span><span>Menu3</span>
</div>
If you want that your script searches for that "Menu1" you should consider adding that "Menu1" as an attribute on the span or parentNode.
<div id="Menu1">
<span>Home1</span>
</div>
and then call
document.getElementById('Menu1');
Which is very fast.
innerHTML method return String type. It don't associate with DOM tree.
You can use jQuery and it contains selector(fiddle):
$(":contains('Home1')").last()
var divRef; //Reference to the container of your div / span elements
var spans = divRef.getElementsByTagName("span");
var spanContainer;
for(var i = 0; i < spans.length; i++){
if(spans[i].innerHtml == "Home 1"){
spanContainer = spans[i].parentNode;
break;
}
}
if(spanContainer){
alert("Element has been found!");
}
function findNodeByInnerHTML(nodelist, innerHTML){
for(let ii = 0; ii < nodelist.length; ii++){
if(nodelist[ii].innerHTML === innerHTML)
return nodelist[ii]
}
}
let span = findNodeByInnerHTML(document.querySelectorAll('span'), 'home')
I was able to replace the punctuation with span tags and separate the sentences, but I tried to increment the id by one for each sentence and it only worked on the first one.
$('.whatever').each(function(index) {
var sentences = $(this).html().replace(/([^.!?]*[^.!?\s][.!?]['"]?)(\s|$)/g,
'<span id="'+index+'">$1</span>$2<SENTENCE_END>');
$(this).html(sentences);
});
Thanks for any ideas.
If all of your text is inside #whatever, you'll want to first split the text by periods and then iterate through each of those to add <spans>.
Here's an example:
// set counter
var j = 0;
// get text from div
var sentences = $('#whatever').text().trim();
// split text by "."
var sentences = sentences.split('.');
// empty the output div
$('#whatever').empty();
// for each sentence, check for blank sentence,
// add span with counter number, trim spaces,
// add leading space if this is not the first sentence,
// add "." at the end of sentence, output to div
$(sentences).each(function () {
if (this.trim()!='') {
$('#whatever').append( (j>0?" ":"") + '<span class="sentence" id="sentence_' + j + '">' + this.trim() + '.</span>');
j++;
}
});
http://jsfiddle.net/FrDzL/1/
Why are you using the id selector? The id selector $('#whatever') only selects one element (the first element matching the id on the page). Hence that each loop is only executed once (that's why it only worked in the first one).
Modify your html code to use classes, and select using $('.whatever').
ID Selector (“#id”)
Selects a single element with the given id attribute.
Source: http://api.jquery.com/id-selector/
Try the following
HTML
<p class="whatever">hej</p>
<br>
<p class="whatever">hej</p>
<br>
<p class="whatever">hej</p>
JS
var j = 0;
$('.whatever').each(function() {
var sentences = $(this).html().replace('hej','nej');
j++;
$(this).html(sentences);
});
JSFiddle
And finally, working code for your example
var j = 0;
$('.whatever').each(function() {
var sentences = $(this).html().replace(/([^.!?]*[^.!?\s][.!?]['"]?)(\s|$)/g,
'<span class="sentence" id="'+j+'">$1</span>$2<SENTENCE_END>');
j++;
$(this).html(sentences);
});