Javascript regex to replace text div and < > - javascript

var text='<div id="main"><div class="replace">< **My Text** ></div><div>Test</div></div>'
I want to replace div with class="replace" and html entities < > comes inside that div with some other text.
I.e the output :
'<div id="main"> Hello **My Text** Hello <div>Test</div> </div>'
I've tried
var div = new RegExp('<[//]{0,1}(div|DIV)[^><]*>', 'g');
text = text.replace(div, "Hello");
but this will replace all div.
Any help gratefully received!

If a Jquery solution is acceptable:
text = $(text) // Convert HTML string to Jquery object
.wrap("<div />") // Wrap in a container element to make...
.parent() // the whole element searchable
.find("div.replace") // Find <div class="replace" />
.each(function() // Iterate over each div.replace
{
$(this)
.replaceWith($(this).html() // Replace div with content
.replace("<", "<sometext>")
.replace(">", "</sometext>")); // Replace text
})
.end().html(); // return html of $(text)
This sets text to:
<div id="main"><sometext> My Text </sometext><div>Test</div></div>
And to replace it back again:
text = text.replace('<sometext>', '<div class="replace"><')
.replace('</sometext>', '></div>');
http://api.jquery.com/jquery/#jQuery2
http://api.jquery.com/each/
http://api.jquery.com/find/
http://api.jquery.com/html/

In pure JS it will be something like this:
var elements = document.getElementsByClassName('replace');
var replaceTag = document.createElement('replacetext');
for (var i = elements.length - 1; i >= 0; i--) {
var e = elements[i];
e.parentNode.replaceChild(replaceTag, e);
};​

Here is one crazy regex which matches what you want:
var text='<div id="main"><div class="replace">< **My Text** ></div><div>Test</div></div>'
var r = /(<(div|DIV)\s+class\s*?=('|")\s*?replace('|")\s*?>)(\s*?<)(.*?)(>\s*?)(<\/(div|DIV)\s*?>)/g;
The whole replacement can be made with:
text.replace(r, function () {
return 'Hello' + arguments[6] + 'Hello';
});
Please let me know if there are issues with the solution :).
Btw: I'm totally against regexes like the one in the answer...If you have made it with that complex regex there's probably better way to handle the problem...

Consider using the DOM instead; you already have the structure you want, so swap out the node itself (borrowing heavily from #maxwell's code, but moving children around as well):
var elements = document.getElementsByClassName('replace');
for(var i = elements.length-1; i>= 0; --i) {
var element = elements[i];
var newElement = document.createElement('replacetext');
var children = element.childNodes;
for(var ch = 0; ch < children.length; ++i) {
var child = children[ch];
element.removeChild(child);
newElement.appendChild(child);
}
element.parentNode.insertBefore(newElement,element);
element.parentNode.removeChild(element);
}
For each element of the given class, then, it will move each of its children over to the new element before using that element's position to insert the new element and finally removing itself.
My only questionmark is whether the modification of items in the array return by getElementByClassName will cause problems; it might need an extra check to see if the element is valid before processing it, or you may prefer to write this as a recursive function and process the tree from deepest node first.
It may seem like more work, but this should be faster (no re-parsing of the html after you've changed it, element moves are just reference value assignments) and much more robust. Attempting to parsing HTML may damage your health.
Rereading the question (always a good plan), you begin with the text in a string. If that is truly the start point (i.e. you're not just pulling that out of an innerHTML value), then to use the above just create a temporary parent element:
var fosterer = document.createElement('div');
fosterer.innerHTML = text; // your variable from the question
And then proceed using fosterer.getElementsByClassName.

Related

Finding index in array based on DIV text

I have a DIV which has text in it:
<div id="x">
divText
</div>
I have a "header row" like this:
var headerRow = ["wrong","wrongAgain","divText"];
I also have an array like this:
var theArray = [["blah","blah","0"]["notIt","blahblah","1"],["unrelated","dontLook","0"]];
I want to find the index in theArray (2) based on the text within the div:
var theDiv = x.innerHTML;
for (i=0; i < headerRow.length; i++){
if (headerRow[i] == theDiv){ <--never works
if (headerRow[i] == x.innerHTML) { <---never works
if (headerRow[i] == "divText") { <--works (i = 2)
}
How can I find the index based on the innerHTML of a div / variable (first two cases above)? Thanks!
You are using innerHTML where as which returns content of HTML element including spaces and new lines.Instead use innerText or use methods trim method on either innerHTML or textContent.
In your case the comparision is not successful because the text that you are extracting using innerHTML contains spaces and newline.
Note:If element ID is valid identifier it can be used directly as
window.elementid or just elementid but it's best practice to use getElementByID
var x = document.getElementById('x')
var theDiv = x.innerHTML.trim();
for (i=0; i < headerRow.length; i++){
if (headerRow[i] == theDiv) {
// your codes goes here
console.log('works')
}
}
or You can use
var theDiv = x.innerText
or
var theDiv = x.textContent.trim()
<div id="x">
divText
</div>
<script>
var headerRow = ["wrong","wrongAgain","divText"];
var theDiv = document.getElementById('x').innerHTML;
console.log(theDiv);
for (i=0; i < headerRow.length; i++){
if (headerRow[i] == theDiv.trim()){
console.log(headerRow.indexOf(headerRow[i]));
console.log(i);
}
}
</script>
Your if comparison doesn't work because of extra whitespace/new line in the div's innerHTML text. Thus you need to trim the string before comparing it with the contents of the header row array. Note that you can either use the indexOf method to get the index of the matching element, or you can just use the current value of i, which would also correspond to the index of that element. Hope this makes sense to you.
To get the text from div you should get element by id first
var theDiv = document.getElementById("x").innerHTML
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById
It will work with 1sth array, and the 2nd nested array can be flattened first
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

Assigning javascript array elements class or id for css styling

I'm trying to assign class and id to items in an array I created in js and input into my html. I'm doing this so I can style them in my stylesheet. Each item will not be styled the same way.
I'm a beginner so trying to keep it to code I can understand and make it as clean as possible, i.e. not making each of these items an element in the html.
This part works fine:
var pool =['A','B','3','J','R','1','Q','F','5','T','0','K','N','C','R','U']
var letters = pool.join('');
document.getElementById('key').innerHTML = letters;
This part not so much:
var char1 = letters[1];
char1.classList.add('hoverRed');
There is a similar question here that didn't work for me, it just showed [object][object][object] when I ran it.
Your code attempts to apply a style to an array element, but CSS only applies to HTML. If you wish to style one character in a string, that character must be wrapped in an HTML element (a <span> is the best choice for wrapping an inline value).
This code shows how to accomplish this:
var pool =['A','B','3','J','R','1','Q','F','5','T','0','K','N','C','R','U']
var letters = pool.join('');
// Replace a specific character with the same character, but wrapped in a <span>
// so it can be styled
letters = letters.replace(letters[1], "<span>" + letters[1] + "</span>");
// Insert the letters string into the div
var theDiv = document.getElementById('key');
// Inject the string into the div
theDiv.innerHTML = letters;
// Get a reference to the span:
var theSpan = theDiv.querySelector("span");
// Add the style to the <span> that wraps the character, not the character itself
theSpan.classList.add('hoverRed');
.hoverRed {
color:red;
}
<div id="key"></div>
And, this snippet shows how you could apply CSS to any letter:
var pool =['A','B','3','J','R','1','Q','F','5','T','0','K','N','C','R','U'];
// Leave the original array alone so that it can be manipulated any way needed
// in the future, but create a new array that wraps each array element within
// a <span>. This can be accomplished in several ways, but the map() array method
// is the most straight-forward.
var charSpanArray = pool.map(function(char){
return "<span>" + char + "</span>";
});
// Decide which character(s) need CSS applied to them. This data can come from anywhere
// Here, we'll just say that the 2nd and 5th ones should.
// Loop through the new array and on the 2nd and 5th elements, apply the CSS class
charSpanArray.forEach(function(element, index, array){
// Check for the particular array elements in question
if(index === 1 || index === 4){
// Update those strings to include the CSS
array[index] = element.replace("<span>","<span class='hoverRed'>");
}
});
// Now, turn the new array into a string
var letters = charSpanArray.join('');
// For diagnostics, print the string to the console just to see what we've got
console.log(letters);
// Get a reference to the div container
var theDiv = document.getElementById('key');
// Inject the string into the div
theDiv.innerHTML = letters;
.hoverRed {
color:red;
}
<div id="key"></div>
You're on the right track, but missed one key thing.
In your example, pool contains characters. When you combine them using join, you get a string. Setting that string as the innerHTML of an element doesn't give the string super powers, it's still just a string.
In order to get a classList, you need to change your letters into elements and work with them.
I've included an es6 example (and a working plunker) of how to get the functionality you want below.
let pool = ['A','B','3','J','R','1','Q','F','5','T','0','K','N','C','R','U']
const letterToElement = function(char) {
//Create the element
let e = document.createElement("SPAN");
//Create the text node
let t = document.createTextNode(char);
//Put the text node on the element
e.appendChild(t);
//Add the class name you want
e.className += "hoverRed";
return e;
};
//create your elements from your pool and append them to the "key" element
window.onload = function() {
let container = document.getElementById("key");
pool.map(l => letterToElement(l))
.forEach(e => container.appendChild(e));
}
https://plnkr.co/edit/mBhA60aUCEGSs0t0MDGu

Find child element's index in the HTML markup

I want to find the actual index (in the HTML markup) where a child of a element is located.
Say I have the following markup:
<p id="foo">Lorem <i>ipsum</i> d<strong>ol</strong>ar</p>
And the following code:
var $foo = $('#foo');
var children = $foo.children();
for (var i = 0; i < children.length; i++) {
console.log(children[i]);
}
This outputs the elements <i>ipsum</i> and <strong>ol</strong>. Is there any way to calculate that these elements start at the HTML index 6 and 20 of the parent element #foo? I would like to avoid using a REGEX approach based on the tagName of the element, but that is the only solution I've come up with this far.
Are there any solutions/APIs that I've overlooked that can solve this without overcomplicating things too much? I'd like to make this as generic as possible, with the support of nested tags too, where e.g. #foo > i is the base element and I look inside it to see if there are any nested tags there.
It is also kind of tricky to Google this as most questions/answers deals with actual position, and not the position in the HTML markup.
Working example:
var $foo = $('#foo');
var startIndex = 0;
var children = $foo.children();
for (var i = 0; i < children.length; i++) {
console.log($foo.html());
console.log('<' + $(children[i]).get(0).tagName.toLowerCase());
var this_index = $foo.html().substr(startIndex).indexOf('<' + $(children[i]).get(0).tagName.toLowerCase());
console.log(startIndex + this_index);
console.log('----');
// Update startIndex (to avoid returning the first occurence if multiple children of same type)
startIndex = this_index;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="foo">Lorem <i>ipsum</i> d<strong>ol</strong>ar</p>
Output:
Lorem <i>ipsum</i> d<strong>ol</strong>ar
<i
6
----
Lorem <i>ipsum</i> d<strong>ol</strong>ar
<strong
20
----
However, this is a rather ugly solution and is based on string matching. Is there any way of doing this search/match based on the child element instead? That would limit the possibility that the markup is invalid (for example capitalized HTML tag).
$foo.html().indexOf(children[i].outerHTML) should work
You could simply use indexOf on the string containing inner html of the parent node and search for string containing outer html of the child node:
var haystack = document.querySelector('#foo');
var needle = haystack.querySelector('i');
var startIndex = haystack.innerHTML.indexOf(needle.outerHTML);
var endIndex = startIndex + needle.outerHTML.length;
document.writeln('start: ' + startIndex + '<br> end: ' + endIndex);
<p id="foo">Lorem <i>ipsum</i> d<strong>ol</strong>ar</p>
Similarly it also works if you replace i with strong and yields start: 20 end:39

How to correctly use innerHTML to create an element (with possible children) from a html string?

Note: I do NOT want to use any framework.
The goal is just to create a function that will return an element based on an HTML string.
Assume a simple HTML Document like such:
<html>
<head></head>
<body>
</body>
</html>
All functions mentioned are in included the head section and all DOM creation/manipulation is done at the end of the body in a script tag.
I have a function createElement that takes a well formed HTML String as an argument. It goes like this:
function createElement(str)
{
var div = document.createElement('div');
div.innerHTML = str;
return div.childNodes;
}
Now this functions works great when you call it like such:
var e = createElement('<p id="myId" class="myClass">myInnerHTML</p>');
With the minor (possibly HUGE) problem that the element created isn't a 'true' element, it still has a parentNode of 'div'. If anyone knows how to fix that, then that would be awesome.
Now if I call the same function with a more complex string:
var e = createElement('<p id="myId" class="myClass">innerHTML<h2 id="h2ID" class="h2CLASS">Heading2</h2></p>');
It creates TWO children instead of ONE child with another child having another child.Once you do div.innerHTML = str. The innerHTML instead of
`<p id="myId" class="myClass">innerHTML <h2 id="h2ID" class="h2CLASS">Heading2</h2> </p>`
turns to
`<p id="myId" class="myClass">innerHTML</p> <h2 id="h2ID" class="h2CLASS">Heading2</h2>`
Questions:
Can I somehow get an element without a parent node after using .innerHTML?
Can I (in the case of the slightly complex string) get my function to return ONE element with the appropriate child instead of two elements. [It actually returns three, <p.myClass#myId>,<h2.h2CLASS#h2ID>, and another <p>]
This is similar to the answer from palswim, except that it doesn't bother with creating a clone, and uses a while() loop instead, always appending the node at [0].
function createElement( str ) {
var frag = document.createDocumentFragment();
var elem = document.createElement('div');
elem.innerHTML = str;
while (elem.childNodes[0]) {
frag.appendChild(elem.childNodes[0]);
}
return frag;
}
You'd have to attach the new element somewhere. Try using a DocumentFragment object in conjunction with the div you created:
function createElement(str) {
var div = document.createElement('div');
div.innerHTML = str;
var container = document.createDocumentFragment();
for (var i=0; i < div.childNodes.length; i++) {
var node = div.childNodes[i].cloneNode(true);
container.appendChild(node);
}
return container.childNodes;
}
It's more overhead, but it does what you want. Note that DOM elements' .insertAdjacentHTML member function is coming in HTML5.
For that complex string you passed, it isn't valid XHTML syntax - you can't have a block element as a child of <p> (<h2> is a block level element).

Get element by id with regex

I had a quick question regarding RegEx...
I have a string that looks something like the following:
"This was written by <p id="auth">John Doe</p> today!"
What I want to do (with javascript) is basically extract out the 'John Doe' from any tag with the ID of "auth".
Could anyone shed some light? I'm sorry to ask.
Full story:
I am using an XML parser to pass data into variables from a feed. However, there is one tag in the XML document () that contains HTML passed into a string. It looks something like this:
<item>
<title>This is a title</title>
<description>
"By <p id="auth">John Doe</p> text text text... so on"
</description>
</item>
So as you can see, I can't use an HTML/XML parser for that p tag, because it's in a string, not a document.
Here's a way to get the browser to do the HTML parsing for you:
var string = "This was written by <p id=\"auth\">John Doe</p> today!";
var div = document.createElement("div");
div.innerHTML = string; // get the browser to parse the html
var children = div.getElementsByTagName("*");
for (var i = 0; i < children.length; i++)
{
if (children[i].id == "auth")
{
alert(children[i].textContent);
}
}
If you use a library like jQuery, you could hide the for loop and replace the use of textContent with something cross-browser.
No need of regular expressions to do this. Use the DOM instead.
var obj = document.getElementById('auth');
if (obj)
{
alert(obj.innerHTML);
}
By the way, having multiples id with the same value in the same page is invalid (and will surely result in odd JS behavior).
If you want to have many auth on the same page use class instead of id. Then you can use something like:
//IIRC getElementsByClassName is new in FF3 you might consider using JQuery to do so in a more "portable" way but you get the idea...
var objs = document.getElementsByClassName('auth');
if (objs)
{
for (var i = 0; i < objs.length; i++)
alert(obj[i].innerHTML);
}
EDIT: Since you want to parse a string that contain some HTML, you won't be able to use my answer as-iis. Will your HTML string contain a whole HTML document? Some part? Valid HTML? Partial (broken) HTML?
Perhaps something like
document.getElementById("auth").innerHTML.replace(/<^[^>]+>/g, '')
might work. innerHTML is supported on all modern browsers. (You may omit the replace if you don't care about removing HTML bits from the inner content.)
If you have jQuery at your disposal, just do
$("#auth").text()
What I want to do (with javascript) is
basically extract out the 'John Doe'
from any tag with the ID of "auth".
You can't have the same id (auth) for more than one element. An id should be assigned once per element per page.
If, however, you assign a class of auth to elements, you can go about something like this assuming we are dealing with paragraph elements:
// find all paragraphs
var elms = document.getElementsByTagName('p');
for(var i = 0; i < elms.length; i++)
{
// find elements with class auth
if (elms[i].getAttribute('class') === 'auth') {
var el = elms[i];
// see if any paragraph contains the string
if (el.innerHTML.indexOf('John Doe') != -1) {
alert('Found ' + el.innerHTML);
}
}
}
Assuming you only have 1 auth per string, you might go with something like this:
var str = "This was written by <p id=\"auth\">John Doe</p> today!",
p = str.split('<p id="auth">'),
q = p[1].split('</p>'),
a = q[0];
alert(a);
Simple enough. Split your string on your paragraph, then split the second part on the paragraph close, and the first part of the result will be your value. Every time.
If the content of the tag contains only text, you could use this:
function getText (htmlStr, id) {
return new RegExp ("<[^>]+\\sid\\s*=\\s*([\"'])"
+ id
+ "\\1[^>]*>([^<]*)<"
).exec (htmlStr) [2];
}
var htmlStr = "This was written by <p id=\"auth\">John Doe</p> today!";
var id = "auth";
var text = getText (htmlStr, id);
alert (text === "John Doe");

Categories

Resources