Attributes shouldn't replace when uses replace in javascript - javascript

when I user replace the content with another content the attributes also replacing. Means if you check this URL below, there is a text 'my_text' needs to replace with 'Mark'. Now this replacing but including this the anchor attribute 'my_text' also replacing. So I needs to replace only the content except attributes.
var src_str = $("#test").html();
var term = "mY_text";
term = term.replace(/(\s+)/,"(<[^>]+>)*$1(<[^>]+>)*");
var pattern = new RegExp("("+term+")", "gi");
src_str = src_str.replace(pattern, "<mark>$1</mark>");
src_str = src_str.replace(/(<mark>[^<>]*)((<[^>]+>)+)([^<>]*<\/mark>)/,"$1</mark>$2<mark>$4");
$("#test").html(src_str);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test">this is <a href="mY_text" >my</a> text that needs highlighting my_text</div>

If I'm understanding you correctly, you want to replace the string "my_text" when it appears in the text content, but not when it appears in an attribute.
This is a good example of why it's not a good idea to manipulate HTML with regex: regex doesn't know the difference between DOM nodes and attributes and text. Instead, use DOM traversal methods to find the portions of the DOM you want to modify, and work only on those portions:
// contents() includes text nodes, which is what we want to search through here:
$('#test').contents().each(function() {
// If you were just replacing text, you could simply set this.textContent
// to a new value. But since it looks like you're trying to insert
// a DOM node, we need to convert the text node into a DOM node:
if (this.textContent.indexOf('my_text') > -1) { // there's a match
var replacementNode = document.createElement('span');
// the regex can be simple here, because we know we're working only with text:
var newContent = this.textContent.replace(/(my_text)/,'<mark>$1</mark>');
replacementNode.innerHTML = newContent;
// ... and then replace the text node with the new DOM node:
this.parentNode.insertBefore(replacementNode,this);
this.parentNode.removeChild(this)
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test">this is <a href="my_text" >my</a> text that needs highlighting my_text</div>
(The above will only act on the immediate children of the #test element. If you need to search deeper in the DOM tree, you can use one of the methods shown here to walk through the tree and find the text nodes, then apply the above code to those elements.)

If you want to change the text content use $('a').text('your new text').
If you want to change the href use $('a').attr('href', 'your new url').
There is no relation between the two.

Related

How to remove content within the &lt and &gt javascript

I have a content that contains a string of elements along with images. ex:
var str= <p><img src=\"v\">fwefwefw</img></p><p><br></p><p><br></p>
the text that is within the &lt and &gt is a dirty tag and I would like to remove it along with the content that is within it. the tag is generated dynamically and hence could be any tag i.e <div>, <a>, <h1> etc....
the expected output : <p></p><p><br></p><p><br></p>
however with this code, im only able to remove the tags and not the content inside it.
str.replaceAll(/<.*?>/g, "");
it renders like this which is not what im looking for:
<p>fwefwefw</p><p><br></p><p><br></p><p><br></p>
how can I possibly remove the & tags along with the content so that I get rid of dirty tags and text inside it?
fiddle: https://jsfiddle.net/3rozjn8m/
thanks
A safe way is to use a DOM parser, visiting each text node, where then each text can be cleaned separately. This way you are certain the DOM structure is not altered; only the texts:
let str= "<p><img src=\"v\">fwefwefw</img></p><p><br></p><p><br></p>";
let doc = new DOMParser().parseFromString(str, "text/html");
let walk = doc.createTreeWalker(doc.body, 4, null, false);
let node = walk.nextNode();
while (node) {
node.nodeValue = node.nodeValue.replace(/<.*>/gs, "");
node = walk.nextNode();
}
let clean = doc.body.innerHTML;
console.log(clean);
This will also work when you have more than one <p> element that has such content.
Remove the question mark.
var str= "<p><img src=\"v\">fwefwefw</img></p><p><br></p><p><br></p>";
console.log(str.replaceAll(/<.*>/g, ""));

Find And Change Element In a Parsed HTML DOM

I am getting an HTML string in response to an ajax request. It is a large HTML string with a lot of hierarchical child nodes.
I parse it using
jQuery.parseHTML();
to convert it into a DOM. Now i want to change the content of a child node with a certain ID and then regenerate the HTML.
The Problem is when ever i use a jQuery method to select a dom element to make the changes, it returns that particular node and the
jQuery.html()
just changes that node to HTML.
I have tried following code samples
var parsedHTML = jQuery.parseHTML( 'htmlstring' );
jQuery(parsedHTML).find('#element-id').text('changed text').html();
or
jQuery(parsedHTML).filter('#element-id').text('changed text').html();
the problem is it only returns span#element-id and when html() is applied, the generated html has only span text.
How can i generate back the complete html and change the specific node?
Don't chain (or if you do, use end, but simpler really just not to). By chaining, you're saying you only want the HTML of the last set of elements in the chain:
var elements = jQuery(parsedHTML);
elements.filter('#element-id').text('changed text');
var html = elements.html();
But elements.html() will only give you the inner HTML of the first element. To get the full HTML string again, you need to get the outer HTML of each element and join them together:
var html = elements.map(function() {
return this.outerHTML;
}).get().join("");
Note that your use of filter assumes the element is at the top level of the HTML string. If it is, great, that's fine. If it isn't, you'll want find instead.
Example with filter:
var parsedHTML = jQuery.parseHTML(
"<span>no change</span>" +
"<span id='element-id'>change me</span>" +
"<span>no change</span>"
);
var elements = jQuery(parsedHTML);
elements.filter('#element-id').text('changed text');
console.log(elements.map(function() {
return this.outerHTML;
}).get().join(""));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Example with find:
var parsedHTML = jQuery.parseHTML(
"<span>no change</span>" +
"<div>the span is in here<span id='element-id'>change me</span></div>" +
"<span>no change</span>"
);
var elements = jQuery(parsedHTML);
elements.find('#element-id').text('changed text');
console.log(elements.map(function() {
return this.outerHTML;
}).get().join(""));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to use regex to replace text between tags

I'd like to replace some text in a string that represents a div tag that may or may not also include style and class attributes. For example,
var s = "<div style='xxx' class='xxx'>replaceThisText<div>
If it were just the tag, I believe I could just do this:
str = str.replace(/<div>[\s\S]*?<\/div>/, '<div>' + newText+ '<\/div>');
But how do I take the attributes into account?
Generate a temporary element with your string as HTML content then get the div within it to update content after updating the content get back the HTML of temporary element.
var s = "<div style='xxx' class='xxx'>replaceThisText<div>";
// create a temporary div element
var temp = document.createElement('div');
// set content as string
temp.innerHTML = s;
// get div within the temporary element
// and update the content within the div
temp.querySelector('div').innerHTML = 'newText';
// get back the current HTML content in the
// temporary div element
console.log(temp.innerHTML)
Why not regex?
RegEx match open tags except XHTML self-contained tags
Using regular expressions to parse HTML: why not?
Regex will never be a good decision to parse html content.
Consider the following short solution using DOMParser object(for browsers which support DOMParser implementation, see compatibility table):
var s = "<div style='xxx' class='xxx'>replaceThisText<div>",
tag = (new DOMParser()).parseFromString(s, 'text/html').querySelector('.xxx');
tag.textContent = 'newText'; // replacing with a new text
console.log(tag.outerHTML); // outputs the initial tag representation with replaced content
https://developer.mozilla.org/ru/docs/Web/API/DOMParser

JS - Remove a tag without deleting content

I am wondering if it is possible to remove a tag but leave the content in tact? For example, is it possible to remove the SPAN tag but leave SPAN's content there?
<p>The weather is sure <span>sunny</span> today</p> //original
<p>The weather is sure sunny today</p> //turn it into this
I have tried using this method of using replaceWith(), but it it turned the HTML into
<p>
"The weather is sure "
"sunny"
" today"
</p>
EDIT : After testing all of your answers, I realized that my code is at fault. The reason why I keep getting three split text nodes is due to the insertion of the SPAN tag. I'll create another question to try to fix my problem.
<p>The weather is sure <span>sunny</span> today</p>;
var span=document.getElementsByTagName('span')[0]; // get the span
var pa=span.parentNode;
while(span.firstChild) pa.insertBefore(span.firstChild, span);
pa.removeChild(span);
jQuery has easier ways:
var spans = $('span');
spans.contents().unwrap();
With different selector methods, it is possible to remove deeply nested spans or just direct children spans of an element.
There are several ways to do it. Jquery is the most easy way:
//grab and store inner span html
var content = $('p span').html;
//"Re"set inner p html
$('p').html(content);
Javascript can do the same using element.replace. (I don't remember the regex to do the replace in one stroke, but this is the easy way)
paragraphElement.replace("<span>", "");
paragraphElement.replace("</span>", "");
It's just three text nodes instead of one. It doesn't make a visible difference does it?
If it's a problem, use the DOM normalize method to combine them:
$(...)[0].normalize();
$(function(){
var newLbl=$("p").clone().find("span").remove().end().html();
alert(newLbl);
});​
Example : http://jsfiddle.net/7gWdM/6/
If you're not looking for a jQuery solution, here something that's a little more lightweight and focused on your scenario.
I created a function called getText() and I used it recursively. In short, you can get the child nodes of your p element and retrieve all the text nodes within that p node.
Just about everything in the DOM is a node of some sort. Looking up at the following links I found that text nodes have a numerical nodeType value of 3, and when you identify where your text nodes are, you get their nodeValueand return it to be concatenated to the entire, non-text-node-free value.
https://developer.mozilla.org/en/nodeType
https://developer.mozilla.org/En/DOM/Node.nodeValue
var para = document.getElementById('p1') // get your paragraphe
var texttext = getText(para); // pass the paragraph to the function
para.innerHTML = texttext // set the paragraph with the new text
function getText(pNode) {
if (pNode.nodeType == 3) return pNode.nodeValue;
var pNodes = pNode.childNodes // get the child nodes of the passed element
var nLen = pNodes.length // count how many there are
var text = "";
for (var idx=0; idx < nLen; idx++) { // loop through the child nodes
if (pNodes[idx].nodeType != 3 ) { // if the child not isn't a text node
text += getText(pNodes[idx]); // pass it to the function again and
// concatenate it's value to your text string
} else {
text += pNodes[idx].nodeValue // otherwise concatenate the value of the text
// to the entire text
}
}
return text
}
I haven't tested this for all scenarios, but it will do for what you're doing at the moment. It's a little more complex than a replace string since you're looking for the text node and not hardcoding to remove specific tags.
Good Luck.
If someone is still looking for that, the complete solution that has worked for me is:
Assuming we have:
<p>hello this is the <span class="highlight">text to unwrap</span></p>
the js is:
// get the parent
var parentElem = $(".highlight").parent();
// replacing with the same contents
$(".highlight").replaceWith(
function() {
return $(this).contents();
}
);
// normalize parent to strip extra text nodes
parentElem.each(function(element,index){
$(this)[0].normalize();
});
If it’s the only child span inside the parent, you could do something like this:
HTML:
<p class="parent">The weather is sure <span>sunny</span> today</p>;
JavaScript:
parent = document.querySelector('.parent');
parent.innerHTML = parent.innerText;
So just replace the HTML of the element with its text.
You can remove the span element and keep the HTML content or internal text intact. With jQuery’s unwrap() method.
<html>
<head>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("button").click(function(){
$("p").find("span").contents().unwrap();
});
});
</script>
</head>
<body>
<p>The weather is sure <span style="background-color:blue">sunny</span> today</p>
<button type="button">Remove span</button>
</body>
</html>
You can see an example here: How to remove a tag without deleting its content with jQuery

How to append text to a div element?

I’m using AJAX to append data to a <div> element, where I fill the <div> from JavaScript. How can I append new data to the <div> without losing the previous data found in it?
Try this:
var div = document.getElementById('divID');
div.innerHTML += 'Extra stuff';
Using appendChild:
var theDiv = document.getElementById("<ID_OF_THE_DIV>");
var content = document.createTextNode("<YOUR_CONTENT>");
theDiv.appendChild(content);
Using innerHTML:
This approach will remove all the listeners to the existing elements as mentioned by #BiAiB. So use caution if you are planning to use this version.
var theDiv = document.getElementById("<ID_OF_THE_DIV>");
theDiv.innerHTML += "<YOUR_CONTENT>";
Beware of innerHTML, you sort of lose something when you use it:
theDiv.innerHTML += 'content';
Is equivalent to:
theDiv.innerHTML = theDiv.innerHTML + 'content';
Which will destroy all nodes inside your div and recreate new ones. All references and listeners to elements inside it will be lost.
If you need to keep them (when you have attached a click handler, for example), you have to append the new contents with the DOM functions(appendChild,insertAfter,insertBefore):
var newNode = document.createElement('div');
newNode.innerHTML = data;
theDiv.appendChild(newNode);
If you want to do it fast and don't want to lose references and listeners use: .insertAdjacentHTML();
"It does not reparse the element it is being used on and thus it does not corrupt the existing elements inside the element. This, and avoiding the extra step of serialization make it much faster than direct innerHTML manipulation."
Supported on all mainline browsers (IE6+, FF8+,All Others and Mobile): http://caniuse.com/#feat=insertadjacenthtml
Example from https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
// <div id="one">one</div>
var d1 = document.getElementById('one');
d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');
// At this point, the new structure is:
// <div id="one">one</div><div id="two">two</div>
If you are using jQuery you can use $('#mydiv').append('html content') and it will keep the existing content.
http://api.jquery.com/append/
IE9+ (Vista+) solution, without creating new text nodes:
var div = document.getElementById("divID");
div.textContent += data + " ";
However, this didn't quite do the trick for me since I needed a new line after each message, so my DIV turned into a styled UL with this code:
var li = document.createElement("li");
var text = document.createTextNode(data);
li.appendChild(text);
ul.appendChild(li);
From https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent :
Differences from innerHTML
innerHTML returns the HTML as its name indicates. Quite often, in order to retrieve or write text within an element, people use innerHTML. textContent should be used instead. Because the text is not parsed as HTML, it's likely to have better performance. Moreover, this avoids an XSS attack vector.
Even this will work:
var div = document.getElementById('divID');
div.innerHTML += 'Text to append';
An option that I think is better than any of the ones mentioned so far is Element.insertAdjacentText().
// Example listener on a child element
// Included in this snippet to show that the listener does not get corrupted
document.querySelector('button').addEventListener('click', () => {
console.log('click');
});
// to actually insert the text:
document.querySelector('div').insertAdjacentText('beforeend', 'more text');
<div>
<button>click</button>
</div>
Advantages to this approach include:
Does not modify the existing nodes in the DOM; does not corrupt event listeners
Inserts text, not HTML (Best to only use .insertAdjacentHTML when deliberately inserting HTML - using it unnecessarily is less semantically appropriate and can increase the risk of XSS)
Flexible; the first argument to .insertAdjacentText may be beforebegin, beforeend, afterbegin, afterend, depending on where you'd like the text to be inserted
you can use jQuery. which make it very simple.
just download the jQuery file add jQuery into your HTML
or you can user online link:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
and try this:
$("#divID").append(data);
The following method is less general than others however it's great when you are sure that your last child node of the div is already a text node. In this way you won't create a new text node using appendData MDN Reference AppendData
let mydiv = document.getElementById("divId");
let lastChild = mydiv.lastChild;
if(lastChild && lastChild.nodeType === Node.TEXT_NODE ) //test if there is at least a node and the last is a text node
lastChild.appendData("YOUR TEXT CONTENT");
java script
document.getElementById("divID").html("this text will be added to div");
jquery
$("#divID").html("this text will be added to div");
Use .html() without any arguments to see that you have entered.
You can use the browser console to quickly test these functions before using them in your code.
Why not just use setAttribute ?
thisDiv.setAttribute('attrName','data you wish to append');
Then you can get this data by :
thisDiv.attrName;

Categories