Javascript - How to style specific word in a string of text? - javascript

I have a string of text here that will be dynamically generated to be one of the following:
<h1 id="headline">"Get your FREE toothbrush!"</h1>
OR
<h1 id="headline">"FREE floss set and dentures!"</h1>
Since this will be dynamically generated I won't be able to wrap a <span> around the word "FREE" so I want to specifically target the word "FREE" using Javascript so that I can style it with a different font-family and font-color than whatever styling the <h1> is set to. What methods do I use to go about doing this?

You can search and replace the substring 'FREE' with styled HTML. If 'FREE' occurs more than once in the string you may need to use regex (unless you don't need to support Internet Explorer). See How to replace all occurrences of a string?
In your case:
let str = '<h1 id="headline">"FREE floss set and dentures!"</h1>'
str = str.replace(/FREE/g, '<span color="red">FREE</span>');

The property you are looking for is innerHTML, look the following example:
var word = document.getElementById('word');
function changeWord(){
word.innerHTML = "another";
word.style.backgroundColor = 'black';
word.style.color = 'white';
}
<h1 id="headline">
<span id="word">some</span> base title
</h1>
<button onClick="changeWord()">
change
</button>

Here is a working example using slice and some classic concatenation.
EDIT: Code for the second string is also included now.
//get headline by id
var headline = document.getElementById("headline");
//declare your possible strings in vars
var string1 = "Get your FREE toothbrush!"
var string2 = "FREE floss set and dentures!"
//declare formatted span with "FREE" in var
var formattedFree = "<span style='color: blue; font-style: italic;'>FREE</span>"
//target positions for the rest of your string
var string1Position = 13
var string2Position = 4
//concat your vars into expected positions for each string
var newString1 = string1.slice(0, 9) + formattedFree + string1.slice(string1Position);
var newString2 = formattedFree + string2.slice(string2Position)
//check if strings exist in html, if they do then append the new strings with formatted span
if (headline.innerHTML.includes(string1)) {
headline.innerHTML = newString1
}
else if (headline.innerHTML.includes(string2)) {
headline.innerHTML = newString2
}
<!-- As you can see the original string does not have "FREE" formatted -->
<!-- Change this to your other string "FREE floss set and dentures!" to see it work there as well -->
<h1 id="headline">Get your FREE toothbrush!</h1>

You can split the text and convert the keyword "FREE" to a span element. So you can style the keyword "FREE". This method is safe because does not alter any non-text html element.
var keyword = "FREE";
var headline = document.getElementById("headline");
var highlight, index;
headline.childNodes.forEach(child => {
if (child.nodeType == Node.TEXT_NODE) {
while ((index = child.textContent.indexOf(keyword)) != -1) {
highlight = child.splitText(index);
child = highlight.splitText(keyword.length);
with(headline.insertBefore(document.createElement("span"), highlight)) {
appendChild(highlight);
className = 'highlight';
}
}
}
});
.highlight {
/* style your keyword */
background-color: yellow;
}
<div id="FREE">
<h1 id="headline">"Get your FREE toothbrush! FREE floss set and dentures!"</h1>
</div>

Related

Split multiple class with same name using loop

I have a multiple tag in my webpage with the same class called price. Each tag is of that form
<p class="price">Price: 45$</p>
<p class="price">Price: 32$</p>
What I need at the end is to separate the price text in a span and the price in another so that it will be like that
<p class="price"><span class='h1'>Price:</span> <span class="h2">45$</span></p>
This is what I do until now but problem is that the span is not a tag but is insert as a simple string
let price = $(".price");
for (let i = 0; i < price.length; i++) {
let priceTitle = price[i].innerText.split(":")[0];
let priceToPay = price[i].innerText.split(":")[1];
price[i].innerText = ''; //Delete content of price
$(".price")[i].append("<span class='h1'>"+ priceTitle+"</span> <span class='h2'>"+ priceToPay +"</span>");
}
}
Can you help me fix this issue and perhaps optimize the code I already do.
You've just a few syntax errors e.g. you've set priceToPay then used price_toPay in your final line of code. Also jQuery.append() method is setting your content as textContent and not HTML but just use innerHTML instead. I've added a button for you to click so you can see the before and after effects. See below
window.onload = () => {
document.getElementById('mybutton').addEventListener('click', doFormat);
}
function doFormat() {
let price = $(".price");
for (let i = 0; i < price.length; i++) {
const priceTextContentArray = price[i].innerText.split(":");
let priceTitle = priceTextContentArray[0];
let priceToPay = priceTextContentArray[1];
price[i].innerHTML =
"<span class='h1'>" +
priceTitle +
"</span> <span class='h2'>" +
priceToPay +
"</span>";
}
}
.h1 {
background-color: skyblue;
}
.h2 {
background-color: coral;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer" defer></script>
<button id='mybutton'>Format</button><br>
<p class="price">Price: 45$</p>
<p class="price">Price: 32$</p>
If you want to do it "the jQuery way", to build elements from strings you must use the $ constructor:
replace:
price[i].innerText = ''; //Delete content of price
$(".price")[i].append("<span class='h1'>"+ priceTitle+"</span> <span class='h2'>"+ priceToPay +"</span>");
by:
$(price[i]).html('').append( $("<span class='h1'>"+ priceTitle +"</span> <span class='h2'>"+ priceToPay +"</span>") );
As you see in jQuery you can also chain the calls, and use the .html() or .text() dedicated functions. html is more suitable here as you want to delete all inside your element, not just the text part
Notice that I also corrected your $(".price")[i] to $(price[i]), it is safer to use the var you loop on instead of doing a new jQuery selection and assume it will have the same index as in your loop

Target last word and wrap with span class

I am trying to target the last word within a class and then wrap it with a span so that I can style the last word using Javascript.
<h1 class="title>A long tile</h1>
<h2 class="title>A long tile</h2>
becomes
<h1 class="title>A long <span class="last-word">tile</span></h1>
<h2 class="title>A long <span class="last-word">tile</span></h2>
I've seen some jQuery solutions on Stack which helped a bit, but I'd like a JS version.
I can get this working for the first element on the page, using this codeā€¦
var paras = document.querySelector('.title');
function wrapLastWord(elem) {
const textContent = elem.textContent.split(" ");
const lastWord = textContent.pop();
// if the sentence is more than 1 word, wrap the last word with a span. If it's only 1 word, return it without being wrapped by a span
const updatedContent = textContent.join(" ") + (textContent.length > 0 ? ` <span class='last-word'>${lastWord}</span>` : lastWord);
elem.innerHTML = updatedContent;
}
wrapLastWord(paras)
However, I want to target all classes of .title and hence I thought I could use a querySelectorAll and a forEach. I am clearly not understanding how this works.
var paras = document.querySelectorAll('.title');
paras.forEach(function wrapLastWord(elem) {
const textContent = elem.textContent.split(" ");
const lastWord = textContent.pop();
// if the sentence is more than 1 word, wrap the last word with a span. If it's only 1 word, return it without being wrapped by a span
const updatedContent = textContent.join(" ") + (textContent.length > 0 ? ` <span class='last-word'>${lastWord}</span>` : lastWord);
elem.innerHTML = updatedContent;
}
wrapLastWord(paras)
})
Could anyone please give me some pointers to get this working, or suggest an alternative direction
To begin you have a syntax error in your second line missing an "
<h1 class="title>A long <span class="last-word">tile</span></h1>
<h2 class="title>A long <span class="last-word">tile</span></h2>
should be this
<h1 class="title">A long <span class="last-word">tile</span></h1>
<h2 class="title">A long <span class="last-word">tile</span></h2>
As for getting the value using javascript you can simply do
const spanText = document.querySelector('.last-word).innerText
// this will find the first match
console.log(spanText)
//if you want to find all of the ".last-words"
const lastWords = document.querySelectorAll('.last-word')
console.log(lastWords, "<-array like object")
lastWords.forEach((word)=> {
console.log(word.innerText)
})
As for your function
var paras = document.querySelectorAll(".title");
console.log(paras);
paras.forEach(function wrapLastWord(elem) {
const textContent = elem.innerText.split(" ");
console.log(textContent, ' textContent')
const lastWord = textContent.pop();
console.log(lastWord, 'last word')
// // if the sentence is more than 1 word, wrap the last word with a span. If it's only 1 word, return it without being wrapped by a span
const updatedContent = ` <span class='last-word'>${lastWord}</span>`;
console.log(updatedContent, 'updatedContent')
})
You've created updatedContent as you can see in your log, but now you have to decide what you want to do with it. Maybe use one of the append methods you can look at the docs and explore the append method if you want to add it to your page
#JimithyPicker Thanks, you led me to an answer.
My final code is as follows:
const paras = document.querySelectorAll(".title");
paras.forEach(function wrapLastWord(elem) {
const textContent = elem.textContent.split(" ");
const lastWord = textContent.pop();
// if the sentence is more than 1 word, wrap the last word with a span. If it's only 1 word, return it without being wrapped by a span
const updatedContent = textContent.join(" ") + (textContent.length > 0 ? ` <span class='last-word'>${lastWord}</span>` : lastWord);
elem.innerHTML = updatedContent;
});

How to make a word count that contains html tags using javascript?

Hi I would like to do a Word Count in my RTE (Rich Text Editor) with javascript can also use with jquery. But it should not count the html tags and repeating white spaces.
Sample Text:
<p>11 22 33</p><p>44</p>5<br></div>
The javascript should display 5 only.
Is there any javascript code for this and that is also fast to calculate the Word Count?
Thanks!
Try something like this:
You get the html in the div then you remove all tags and replace them with spaces. You remove (trim) all left and right spaces and finally you split the string into an array. The length is your answer.
var cont = $("#content").html();
cont = cont.replace(/<[^>]*>/g," ");
cont = cont.replace(/\s+/g, ' ');
cont = cont.trim();
var n = cont.split(" ").length
alert(n);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="content">
<p>11 22 33</p><p>44</p>5<br></div>
var words = [];
function getWords(elements) {
elements.contents().each(function() {
if ($(this).contents().length > 0) return getWords($(this));
if ($(this).text()) words = words.concat($(this).text().split(" "));
})
}
getWords($('<div>').html('<p>11 22 33</p><p>44</p>5<br></div>'));
console.log(words,words.length);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can do something tricky by using jQuery by creating an element with the content.
var str = '<p>11 22 33</p><p>44</p>5<br></div>';
var len = 0;
// create a temporary jQuery object with the content
$('<div/>', {
html: str
})
// get al child nodes including text node
.contents()
// iterate over the elements
.each(function() {
// now get number or words using match and add
len += (this.textContent.match(/[\w\d]+/g) || '').length;
});
console.log(len);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can use Countable.js for live word counting, although it doesn't ignore HTML tags.

Better way of extracting text from HTML in Javascript

I'm trying to scrape text from an HTML string by using container.innerText || container.textContent where container is the element from which I want to extract text.
Usually, the text I want to extract is located in <p> tags. So for the HTML below as an example:
<div id="container">
<p>This is the first sentence.</p>
<p>This is the second sentence.</p>
</div>
Using
var container = document.getElementById("container");
var text = container.innerText || container.textContent; // the text I want
will return This is the first sentence.This is the second sentence. without a space between the first period and the start of the second sentence.
My overall goal is to parse text using the Stanford CoreNLP, but its parser cannot detect that these are 2 sentences because they are not separated by a space. Is there a better way of extracting text from HTML such that the sentences are separated by a space character?
The HTML I'm parsing will have the text I want mostly in <p> tags, but the HTML may also contain <img>, <a>, and other tags embeeded between <p> tags.
As a dirty hack, try using this:
container.innerHTML.replace(/<.*?>/g," ").replace(/ +/g," ");
This will replace all tags with a space, then collapse multiple spaces into a single one.
Note that if there is a > inside an attribute value, this will mess you up. Avoiding this problem will require more elaborate parsing, such as looping through all text nodes and putting them together.
Longer but more robust method:
function recurse(result, node) {
var c = node.childNodes, l = c.length, i;
for( i=0; i<l; i++) {
if( c[i].nodeType == 3) result += c.nodeValue + " ";
if( c[i].nodeType == 1) result = recurse(result, c[i]);
}
return result;
}
recurse(container);
Assuming I haven't made a stupid mistake, this will perform a depth-first search for text nodes, appending their contents to the result as it goes.
jQuery has the method text() that does what you want. Will this work for you?
I'm not sure if it fits for everything that's in your container but it works in my example. It will also take the text of a <a>-tag and appends it to the text.
Update 20.12.2020
If you're not using jQuery. You could implement the text method with vanilla js like this:
const nodes = Array.from(document.querySelectorAll("#container"));
const text = nodes
.filter((node) => !!node.textContent)
.map((node) => node.textContent)
.join(" ");
Using querySelectorAll("#container") to get every node in the container. Using Array.from so we can work with Array methods like filter, map & join.
Finally, generate the text by filtering out elements with-out textContent. Then use map to get each text and use join to add a space separator between the text.
$(function() {
var textToParse = $('#container').text();
$('#output').html(textToParse);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<p>This is the first sentence.</p>
<p>This is the second sentence.</p>
<img src="http://placehold.it/200x200" alt="Nice picture"></img>
<p>Third sentence.</p>
</div>
<h2>output:</h2>
<div id="output"></div>
You can use the following function to extract and process the text as shown. It basically goes through all the children nodes of the target element and the child nodes of the child nodes and so on ... adding spaces at appropriate points:
function getInnerText( sel ) {
var txt = '';
$( sel ).contents().each(function() {
var children = $(this).children();
txt += ' ' + this.nodeType === 3 ? this.nodeValue : children.length ? getInnerText( this ) : $(this).text();
});
return txt;
}
function getInnerText( sel ) {
var txt = '';
$( sel ).contents().each(function() {
var children = $(this).children();
txt += ' ' + this.nodeType === 3 ?
this.nodeValue : children.length ?
getInnerText( this ) : $(this).text();
});
return txt;
}
alert( getInnerText( '#container' ) );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
Some other sentence
<p>This is the first sentence.</p>
<p>This is the second sentence.</p>
</div>
You may use jQuery to traverse down the elements.
Here is the code :
$(document).ready(function()
{
var children = $("#container").find("*");
var text = "";
while (children.html() != undefined)
{
text += children.html()+"\n";
children = children.next();
}
alert(text);
});
Here is the fiddle : http://jsfiddle.net/69wezyc5/

Stack at getting elements with javascript

I have the following html elements from which I have to get some specific texts,
example "John Doe"
I'm a newbie in javascript but have been playing with getElementById etc but I can't seem to get this one right.
<div id="name">
<p><span id="nameheading">name: </span> John Doe</p>
</div>
Bellow is What I have tried:
function askInformation()
{
var nameHeading = document.getElementById("nameheading");
var paragraph = document.getElementsByTagName("p").item(0).innerHTML ;
var name = paragraph[4];
console.log(name); // prints letter (n)
}
I need help please
If you want to get the text following the span in the following:
<div id="name">
<p><span id="nameheading">name: </span> John Doe</p>
</div>
You can use something like:
// Get a reference to the span
var span = document.getElementById('nameheading');
// Get the following text
var text = span.nextSibling.data;
However that is highly dependent on the internal structure, it may be best to loop over text node children and collect the content of all of them. You may also want to trim leading and trailing white space.
You could also get a reference to the parent DIV and use a function like the following that collects the text children and ignores child elements:
// Return the text of the child text nodes of an element,
// but not descendant element text nodes
function getChildText(element) {
var children = element.childNodes;
var text = '';
for (var i=0, iLen=children.length; i<iLen; i++) {
if (children[i].nodeType == '3') {
text += children[i].data;
}
}
return text;
}
var text = getChildText(document.getElementById('name').getElementsByTagName('p')[0]);
or more concisely for hosts that support the querySelector interface:
var text = getChildText(document.querySelector('#name p'));
var paragraph = document.getElementsByTagName("p").item(0).innerHTML ;
var name = paragraph.replace('<span id="nameheading">name: </span>','').trim(); // John Doe

Categories

Resources