Suppose I have this string:
"hello" in a <span> tag, and I want to execute a code for each letter (example: hide, change opacity, etc..). How can I make this with JS/Jquery without having to do this:
<span>h</span><span>e</span><span>l</span><span>l</span><span>o</span>
No and yes. As far as I know, no, a span tag around each letter is necessary, but, yes, you can swing it in JavaScript. A couple examples here, using this concept to randomly apply a color and size to each character.
forEach loop method:
JSFiddle
<span>hello</span>
<script>
var span = document.querySelector('span')
var str = span.innerHTML
span.innerHTML = ''
str.split('').forEach(function (elem) {
var newSpan = document.createElement('span')
newSpan.style.color = "#"+((1<<24)*Math.random()|0).toString(16)
newSpan.style.fontSize = (Math.random() * (36 - 10) + 10) + 'px'
newSpan.innerHTML = elem
span.appendChild(newSpan)
})
</script>
setTimeout method:
JSFiddle
<span>hello</span>
<script>
var span = document.querySelector('span')
var str_arr = span.innerHTML.split('')
span.innerHTML = ''
var ii = 0
~function crazy(ii, str_arr, target) {
if ( ii < str_arr.length ) {
var newSpan = document.createElement('span')
newSpan.style.color = "#"+((1<<24)*Math.random()|0).toString(16)
newSpan.style.fontSize = (Math.random() * (72 - 36) + 36) + 'px'
newSpan.innerHTML = str_arr[ii]
target.appendChild(newSpan)
setTimeout(function () {
crazy(ii += 1, str_arr, target)
}, 1000)
}
}(ii, str_arr, span)
</script>
You can do this.
In html
<span id="my-text">hello</span>
<div id="split-span" ></div>
In Javascript,
var text = $('#my-text').html().split('');
for(var i=0; i<text.length; i++){
$('#split-span').append('<span>'+text[i]+'</span>');
}
You can do this fairly easily in vanilla javaScript without the need of a library like jquery. You could use split to convert your string into an array. This puts each letter into an index of the array. From here you can add markup to each index (or letter) with a loop.
example:
var str = "hello";
var res = str.split('');
for( var i = 0; i < res.length; i++ ){
res[ i ] = '<span>' + res[ i ] + '</span>'
}
Related
How to highlight all the words that the user is searching without affecting the text of the display and the attributes inside the elements. I have tried some approaches but there is a problem as described below. Please help. Thank you. Keep safe and healthy.
<input type='text' id='search' onkeyup="highlight(this.value)">
<p id='WE1'><b>WE</b>wE & theythem and We<span id="we2">we only.</span></p>
function highlight(searchedWords) {
var p = document.getElementById("WE1");
var words = searchedWords.trim().split(" ");
for (var i=0; i < words.length; i++) {
var word = words[i].trim();
/*
searchedWords = "We Only";
trial#1: use replaceAll
p.innerHTML = p.innerHTML.replaceAll(word, "<mark>" + word + "</mark>");
Issues:
1) replaceAll does not work in other browsers
2) It highlights also the tag attributes containing the searchedWords
3) It is case sensitive, it only highlights the exact match, though I've addressed this using this:
var str = p.innerHTML;
for (var j=0; j < words.length; j++) {
var x = words[j].trim(), string = str.toLowerCase();
while (string.lastIndexOf(x) > -1) {
str = str.substring(0, string.lastIndexOf(x)) + "<mark>"
+ str.substr(string.lastIndexOf(x), words[j].length) + "</mark>"
+ str.substring(string.lastIndexOf(x) + words[j].length, str.length);
string = string.substring(0, string.lastIndexOf(x));
}
}
p.innerHTML = str;
4) Changing .toLowerCase() also changes the display to lower case
var x = p.innerHTML.toLowerCase, word = word.toLowerCase;
p.innerHTML = x.replaceAll(word, "<mark>" + word + "</mark>");
trial#2:
p.innerHTML = p.innerHTML.replace(new RegExp(words[i], "gi"), (match) => `<mark>${match}</mark>`);
Issues:
1) OK, it is NOT case sensitive, it highlights all the searchedWords and the display is OK
2) But, it highlights also the tag attributes containing the searchedWord, anchor tags are affected
I tried also using p.childNodes, nodeValue, textContent so that the attributes
containing the searchedWord are not affected yet it only inserts the words
<mark>SearchedWord</mark> and the searchedWord is not highlighted.
*/
}
}
replaceAll is a new feature es2021. As for today it's incompatible with IE.
I found you something that might work. Please have a look and tell me if you still have problems How to replace all occurrences of a string in JavaScript on stackoverflow
I made a workaround by reading the innerHTML from right to left and disregarding the match if there is a "<" character to the left, which means that the match is inside a tag. Although the solution below seems to be manual, yet it works for me for now.
<!DOCTYPE html>
<html>
<input type="text" onkeyup="highlight(this.value)">
<p>Hi! I'm feeling well and happy, hope you too. Thank you.</p>
<p id="WE1"><b>WE</b> wE, We, we.
Only you.
<span id="wemark">mark it in your calendar.</span>
</p>
<script>
function highlight(searchedWords) {
var p = document.getElementsByTagName('p');
for (var i=0; i<p.length; i++) {
p[i].innerHTML = p[i].innerHTML.replace(new RegExp("<mark>", "gi"),(match) => ``);
p[i].innerHTML = p[i].innerHTML.replace(new RegExp("</mark>","gi"),(match) => ``);
}
var words = searchedWords.trim();
while (words.indexOf(" ") > -1) {words = words.replace(" "," ")}
if (!words) return;
words = words.split(" ");
for (var i = 0; i < p.length; i++) {
p[i].innerHTML = mark(p[i].innerHTML, words)
}
}
function mark(str, words) {
try {
for (var j=0; j < words.length; j++) {
var s = str.toLowerCase(),
x = words[j].toLowerCase().trim();
while (s.lastIndexOf(x) > -1) {
var loc = s.lastIndexOf(x), y = loc;
while (y > 0) {
y = y - 1;
if (s.substr(y,1)=="<"||s.substr(y,1)==">") break;
}
if (s.substr(y, 1) != "<") {
str = str.substring(0, loc) + "<mark>"
+ str.substr(loc, x.length) + "</mark>"
+ str.substring(loc + x.length, str.length);
}
s = s.substring(0, loc-1);
}
}
return str;
} catch(e) {alert(e.message)}
}
</script>
</html>
HTML Code
<textarea id="test"></textarea>
<button id="button_test">Ok</button>
Javascript
$(document).ready(function()
{
$("#test").val("123e2oierhqwpoiefdhqwopidfhjcospid");
});
$("#button_test").on("click",function()
{
var as=document.getElementById("test").value;
console.log(as);
});
We can get the values from textarea line by line using val and split functions. But
Is it possible to get the value from textarea line by line for very long word?.In the example i need to get the output as 123e2oierhqwpoiefdhqwo and pidfhjcospid as separate values.
Jsfiddle link here
You can use something like this. This will insert line breaks into into the textarea.
Credits: https://stackoverflow.com/a/4722395/4645728
$(document).ready(function() {
$("#test").val("123e2oierhqwpoiefdhqwopidfhjcospid");
});
$("#button_test").on("click", function() {
ApplyLineBreaks("test");
var as = document.getElementById("test").value;
console.log(as);
});
//https://stackoverflow.com/a/4722395/4645728
function ApplyLineBreaks(strTextAreaId) {
var oTextarea = document.getElementById(strTextAreaId);
if (oTextarea.wrap) {
oTextarea.setAttribute("wrap", "off");
} else {
oTextarea.setAttribute("wrap", "off");
var newArea = oTextarea.cloneNode(true);
newArea.value = oTextarea.value;
oTextarea.parentNode.replaceChild(newArea, oTextarea);
oTextarea = newArea;
}
var strRawValue = oTextarea.value;
oTextarea.value = "";
var nEmptyWidth = oTextarea.scrollWidth;
var nLastWrappingIndex = -1;
for (var i = 0; i < strRawValue.length; i++) {
var curChar = strRawValue.charAt(i);
if (curChar == ' ' || curChar == '-' || curChar == '+')
nLastWrappingIndex = i;
oTextarea.value += curChar;
if (oTextarea.scrollWidth > nEmptyWidth) {
var buffer = "";
if (nLastWrappingIndex >= 0) {
for (var j = nLastWrappingIndex + 1; j < i; j++)
buffer += strRawValue.charAt(j);
nLastWrappingIndex = -1;
}
buffer += curChar;
oTextarea.value = oTextarea.value.substr(0, oTextarea.value.length - buffer.length);
oTextarea.value += "\n" + buffer;
}
}
oTextarea.setAttribute("wrap", "");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="test"></textarea>
<button id="button_test">Ok</button>
Use .match(/pattern/g). As your OP ,pattern should start \w (Find a word character) and match string sequence {start,end}
$("#button_test").on("click",function()
{
var as=document.getElementById("test").value;
console.log(as.match(/(\w{1,22})/g));
});
If you made the textarea width fixed using css you could do this:
css
textarea { resize: vertical; }
javascript
$("#button_test").on("click",function(){
var as=document.getElementById("test").value;
var len = document.getElementById("test").cols;
var chunks = [];
for (var i = 0, charsLength = as.length; i < charsLength; i += len) {
chunks.push(as.substring(i, i + len));
}
console.log(chunks);
});
This is probly not the best way, but it works and i hope it could help you.
First thing, i found the textarea allow 8px for default fontsize charactere.
Exemple :
Textarea with 80px
=> Allow line with 10 char maximum, all other are overflow on new line.
From this you can do a simple function like this :
$("#button_test").on("click",function()
{
console.clear();
var length_area = $("#test").width();
var length_value = $("#test").val().length;
var index = Math.trunc(length_area/8);
var finalstr = $("#test").val().substring(0, index) + " " + $("#test").val().substring(index);
console.log(finalstr);
});
Here the JSFiddle
The <textarea> element has built in functionality to control where words wrap. The cols attribute can be set (either harded coded in the HTML or set with the .attr() method using jQuery). The attribute extends the text area horizontally and it also automatically wraps text at the set value.
Example jsFiddle
$("#test").val("123e2oierhqwpoiefdhqwopidfhjcospid");
var newString = $("#test").val().toString();
var splitString = parseInt($("#test").attr("cols"), 10) + 1;
var stringArray = [];
stringArray.push(newString);
var lineOne = stringArray[0].slice(0, splitString);
var lineTwo = stringArray[0].slice(splitString);
var lineBreakString = lineOne + "\n" + lineTwo;
console.log(lineTwo);
$('#test').after("<pre>" + lineBreakString + "</pre>");
$("#test").val("123e2oierhqwpoiefdhqwopidfhjcospid");
var newString = $("#test").val().toString();
var splitString = parseInt($("#test").attr("cols"), 10) + 1;
var stringArray = [];
stringArray.push(newString);
var lineOne = stringArray[0].slice(0, splitString);
var lineTwo = stringArray[0].slice(splitString);
var lineBreakString = lineOne + "\n" + lineTwo;
$('#test').after("<pre>" + lineBreakString + "</pre>");
//console.log(lineBreakString);
pre {
color: green;
background: #CCC;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<textarea id="test" cols='21'></textarea>
<button id="button_test">Ok</button>
The example addresses the specific question asked. If you want to deal with larger blocks of text, you should use the .each() method and for loops to iterate over each line break.
Documentation:
.slice()
textarea
.push()
.parseInt()
.attr()
I have a string of random 1's and 0's displayed via jQuery. I would now like to select a random number and change it's color. Is it better to work with an array, or a $(div).text() string? I can grab a number from either, but how do I insert it back into the div?
var numbArray = [];
for(i=0; i<10; i++)
{
var randomNumbers = Math.round(Math.random());
$('#numbs').prepend(randomNumbers);
numbArray[i] = randomNumbers;
}
<div id="numbs">0000110111 </div>
The div above is the result of the code, but how do I select a random item, change its color, and display in the original output?
Thanks,
You can locate the number at a certain index, wrap it with the desired color and rebuild the string and set it back to the div using html() and use Math.floor(Math.random() * 10) to generate the random number from zero to the length of the characters you have.
var index = 3;
var originalElementValue;
function colorStringValue(strIndex)
{
strIndex = parseInt(strIndex);
var character = originalElementValue.charAt(strIndex);
$("#numbs").html(originalElementValue.substr(0, strIndex) + "<span style='color:red'>" + character + "</span>" + originalElementValue.substr(strIndex+1));
}
$(document).ready(function(){
originalElementValue = $("#numbs").text();
colorStringValue(index);
$("#strIndex").click(function(){
var rand = Math.floor(Math.random() * 10) + 0 ;
$("#rand").html(rand);
colorStringValue(rand);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="strIndex" > Generate Random Number </button>
<br />
Random Number : <span id="rand"></span>
<br />
<div id="numbs">0000110111</div>
You need to pick a random index from the number string and append some element around that particular number to give it some style.
var number = '0000110111';
var index = Math.floor(Math.random() * number.length);
for(var i = 0; i < number.length; i++) {
var n = number.charAt(i);
if(i == index) {
$('#numbs').append($('<span/>').css('color', 'red').text(n));
} else {
$('#numbs').append(n);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="numbs"></div>
var numbArray = [];
for(i = 0; i< 10; i++) {
var randomNumbers = Math.round(Math.random());
numbArray[i] = randomNumbers;
$('#numbs').prepend(number);
}
var randomNumberSelection = numbArray[Math.floor((Math.random() * (numbArray.length-1)) + 1)];
$('#numbs').html("");
var number;
for(number in numbArray) {
if(number == randomNumberSelection) {
var colorColorCodedNumber = ""+number;
colorColorCodedNumber = colorColorCodedNumber.fontcolor("blue");//blue!
$('#numbs').prepend(colorColorCodedNumber);
} else {
$('#numbs').prepend(number);
}
}
I believe you're looking for something along the lines of this, or at least this is what I took from what you were asking.
In this example be aware you'll see we clear the element then simply reiterate over the array you stored earlier. That is how you 'update' it.
If I understand the question right you want to set a color for a specific position in the div. This means you have to create a span (or another html-element) inside the div at at a random position with a specific color. I havent tested this code below but I guess you could something like this: (in this example red color for the random item)
var randomIndex= Math.floor(Math.random() * 9); //Random number between 0 and 9.
var currentContent = $("#numbs").html();
var randomItem= currentContent.charAt(randomIndex);
newContent = '';
for(i=0; i<10; i++) {
if (i == randomIndex) {
newContent = newContent +
'<span style="background:red;">' + randomItem + '</span>';
}
else {
newContent = newContent + currentContent.charAt(i);
}
}
$("#numbs").html( newContent );
Is this what you are looking for? I just gave it a try. :)
var numbArray = [];
var sample = "<span style='color:#%COLOR%'>%NUM%</span>";
for(i=0; i<10; i++)
{
var randomNumbers = Math.round(Math.random());
var html = sample.replace('%NUM%', randomNumbers);
var randomColor = Math.round((Math.random()* 100000000 )%16777215).toString(16);
html = html.replace('%COLOR%', randomColor);
$('#numbs').prepend(html );
numbArray[i] = randomNumbers;
}
I assumed that you want random colors too.
Good answers by all; thanks! I didn't think of appending the DOM and redisplaying. I went with assigning each number an id and then using css without appending. I was looking for numbers that would turn a color and when all the numbers were that color the script would stop. I don't know which method would perform the best but this way is okay for my limited numbers.
var whiteNumbs =
[0,1,1,0,1,1,0,1,0,1,1,0,0,0,0,1,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0]
for(var i=0; i<whiteNumbs.length; i++)
{
$("#numbs").append('<span class="white" id="num_' + i + '">' +
whiteNumbs[i] + '</span>');
}
function MakeRed()
{
var randomNumber = Math.floor(Math.random() * whiteNumbs.length-1);
var changeCSS = "#num_" + randomNumber;
$(changeCSS).removeClass('white');
$(changeCSS).addClass("red");
if ($("#numbs span").hasClass("white") )
{
setTimeout(MakeRed,1000);
}
else
{
return false;
}
};
MakeRed();
<div id = "board>
<div>{abc</div>
<div>def</div>
<div>ghi}</div>
</div>
I've already done this by span-wrapping all of the char first before comparing if it is { or }. But that is too slow, i need to reverse the procedure, is it possible to get the char position relative to the parent div?
Intended Output is
<div id = "board>
<div><span>{</span>abc</div>
<div>def</div>
<div>ghi<span>}</span></div>
</div>
how about using contains() and replace()?
You want to use Regular Expressions:
var x = '<div id = "board>' +
'<div>{abc</div>' +
'<div>def</div>' +
'<div>ghi}</div>' +
'</div>'; // or... get element by id 'board'
var rgx1 = /{/;
var rgx2 = /}/;
var y = x.replace(rgx1, "<span>{</span>");
y = y.replace(rgx2, "<span>}</span>");
if you think you have more than 1 occurrence of { or }, you can add "g" to the regex's:
var rgx1 = /{/g;
var rgx2 = /}/g;
Assuming this is the markup:
<div id="board">
<div>{abc</div>
<div>def</div>
<div>ghi}<div>
</div>
And your intended output is:
<div id="board">
<span>abcdefghi</span>
</div>
You can do this using jQuery/javascript like this:
var textNodes = $("#board").find("div");
var text = "";
for(var i=0;i<textNodes.length;i++) {
text = text + textNodes[i].text();
$("#board").remove(textNodes[i]);
}
var spans = text.split("}");
var textToAppend = "";
for(i=0;i<spans.length - 1 ;i++)
textToAppend = textToAppend + "<span>"+spans[i].split("{")[1]+"</span>";
$("#board").append(textToAppend);
Is this the solution you are looking for?
Edit 1:
If you need just the position of lets say b as 2, and d as 4?
Here is the code.
var textNodes = $("#board").find("div");
var text = "";
for(var i=0;i<textNodes.length;i++) {
text = text + textNodes[i].text();
}
var codeBlocks = text.split("}");
var firstBlock = codeBlocks[0];
var getCharPosInBlock = function (character) {
if(character === "}") return firstBlock.length;
return firstBlock.indexOf(character);
}
To get the required result using javascript looping:
var textNodes = $("#board").find("div");
for(var i=0;i<textNodes.length;i++) {
var value = textNodes[i].text()
if(value.indexOf("{") > 0)
textNodes[i].text(value.replace("{", "<span>{</span>"));
if(value.indexOf("}") > 0)
textNodes[i].text(value.replace("{", "<span>}</span>"));
}
The following codes doesn't work and the result is broken because there are white spaces in a HTML tag.
HTML:
<div>Lorem ipsum <a id="demo" href="demo" rel="demo">dolor sit amet</a>, consectetur adipiscing elit.</div>
Javascript:
var div = document.getElementsByTagName('div')[0];
div.innerHTML = div.innerHTML.replace(/\s/g, '<span class="space"> </span>');
How to replace replace white spaces which are not in HTML tags?
It would be a better idea to actually use the DOM functions rather than some unreliable string manipulation using a regexp. splitText is a function of text nodes that allows you to split text nodes. It comes in handy here as it allows you to split at spaces and insert a <span> element between them. Here is a demo: http://jsfiddle.net/m5Qe8/2/.
var div = document.querySelector("div");
// generates a space span element
function space() {
var elem = document.createElement("span");
elem.className = "space";
elem.textContent = " ";
return elem;
}
// this function iterates over all nodes, replacing spaces
// with space span elements
function replace(elem) {
for(var i = 0; i < elem.childNodes.length; i++) {
var node = elem.childNodes[i];
if(node.nodeType === 1) {
// it's an element node, so call recursively
// (e.g. the <a> element)
replace(node);
} else {
var current = node;
var pos;
while(~(pos = current.nodeValue.indexOf(" "))) {
var next = current.splitText(pos + 1);
current.nodeValue = current.nodeValue.slice(0, -1);
current.parentNode.insertBefore(space(), next);
current = next;
i += 2; // childNodes is a live array-like object
// so it's necessary to advance the loop
// cursor as well
}
}
}
}
You can deal with the text content of the container, and ignore the markup.
var div = document.getElementsByTagName('div')[0];
if(div.textContent){
div.textContent=div.textContent.replace(/(\s+)/g,'<span class="space"> </span>';
}
else if(div.innerText){
div.innerText=div.innerText.replace(/(\s+)/g,'<span class="space"> </span>';
}
First split the string at every occurrence of > or <. Then fit together all parts to a string again by replacing spaces only at the even parts:
var div = document.getElementsByTagName('div')[0];
var parts = div.innerHTML.split(/[<>]/g);
var newHtml = '';
for (var i = 0; i < parts.length; i++) {
newHtml += (i % 2 == 0 ? parts[i].replace(/\s/g, '<span class="space"> </span>') : '<' + parts[i] + '>');
}
div.innerHTML = newHtml;
Also see this example.
=== UPDATE ===
Ok, the result of th IE split can be different then the result of split of all other browsers. With following workaround it should work:
var div = document.getElementsByTagName('div')[0];
var sHtml = ' ' + div.innerHTML;
var sHtml = sHtml.replace(/\>\</g, '> <');
var parts = sHtml.split(/[<>]/g);
var newHtml = '';
for (var i = 0; i < parts.length; i++) {
if (i == 0) {
parts[i] = parts[i].substr(1);
}
newHtml += (
i % 2 == 0 ?
parts[i].replace(/\s/g, '<span class="space"> </span>') :
'<' + parts[i] + '>'
);
}
div.innerHTML = newHtml;
Also see this updated example.
=== UPDATE ===
Ok, I have completly changed my script. It's tested with IE8 and current firefox.
function parseNodes(oElement) {
for (var i = oElement.childNodes.length - 1; i >= 0; i--) {
var oCurrent = oElement.childNodes[i];
if (oCurrent.nodeType != 3) {
parseNodes(oElement.childNodes[i]);
} else {
var sText = (typeof oCurrent.nodeValue != 'undefined' ? oCurrent.nodeValue : oCurrent.textContent);
var aParts = sText.split(/\s+/g);
for (var j = 0; j < aParts.length; j++) {
var oNew = document.createTextNode(aParts[j]);
oElement.insertBefore(oNew, oCurrent);
if (j < aParts.length - 1) {
var oSpan = document.createElement('span');
oSpan.className = 'space';
oElement.insertBefore(oSpan, oCurrent);
var oNew = document.createTextNode(' ');
oSpan.appendChild(oNew);
}
}
oElement.removeChild(oCurrent);
}
}
}
var div = document.getElementsByTagName('div')[0];
parseNodes(div);
Also see the new example.