I have the following code:
<div class="TopMenu">
<h3>Create an Account</h3>
<h3>yup</h3>
<h3>lol</h3>
yo
<ul>
<li sytle="display:">
start or
finish
</li>
</ul>
and I'm using:
$('.TopMenu li:contains("or")').each(function() {
var text = $(this).text();
$(this).text(text.replace('or', 'triple'));
});
It works fine, but suddenly the links aren't active,
how do I fix it?
Thank you very much in advance.
Here's what your jQuery basically translates to when it's being run:
text = this.textContent;
// text = "\n\t\tstart or\n\t\t finish\n\t\t\n";
text = text.replace('or','triple');
// text = "\n\t\tstart triple\n\t\t finish\n\t\t\n";
this.textContent = text;
// essentially, remove everything from `this` and put a single text node there
Okay, that's not a great explanation XD The point is, setting textContent (or, in jQuery, calling .text()), replaces the element's contents with that text.
What you want to do is just affect the text nodes. I'm not aware of how to do this in jQuery, but here's some Vanilla JS:
function recurse(node) {
var nodes = node.childNodes, l = nodes.length, i;
for( i=0; i<l; i++) {
if( nodes[i].nodeType == 1) recurse(node);
else if( nodes[i].nodeType == 3) {
nodes[i].nodeValue = nodes[i].nodeValue.replace(/\bor\b/g,'triple');
}
}
}
recurse(document.querySelector(".TopMenu"));
Note the regex-based replacement will prevent "boring" from becoming "btripleing". Use Vanilla JS and its magic powers or I shall buttbuttinate you!
Change .text() to .html()
$('.TopMenu li:contains("or")').each(function() {
var text = $(this).html();
$(this).html(text.replace('or', 'triple'));
});
See Fiddle
Since or is a text node, you can use .contents() along with .replaceWith() instead:
$('.TopMenu li:contains("or")').each(function () {
var text = $(this).text();
$(this).contents().filter(function () {
return this.nodeType === 3 && $.trim(this.nodeValue).length;
}).replaceWith(' triple ');
});
Fiddle Demo
You need to us .html() instead of .text(),
Like this:
$('.TopMenu li:contains("or")').each(function() {
var text = $(this).html();
$(this).html(text('or', 'triple'));
});
Here is a live example: http://jsfiddle.net/7Mamj/
jsFiddle Demo
You are placing the anchors into text by doing that. You should iterate the matched elements' childNodes and only use replace on their textContent to avoid modifying any html tags or attributes.
$('.TopMenu li:contains("or")').each(function() {
for(var i = 0; i < this.childNodes.length; i++){
if(this.childNodes[i].nodeName != "#text") continue;
this.childNodes[i].textContent = this.childNodes[i].textContent.replace(' or ', ' triple ');
}
});
It is a bit more complicated task. You need to replace text in text nodes (nodeType === 3), which can be done with contents() and each iteration:
$('.TopMenu li:contains("or")').contents().each(function() {
if (this.nodeType === 3) {
this.nodeValue = this.nodeValue.replace('or', 'triple');
}
});
All other approaches will either rewrite the markup in the <li> element (removing all attached events), or just remove the inner elements.
As discussed in the comments below, fool-proof solution will be to use replacement with regular expression, i.e. this.nodeValue.replace(/\bor\b/g, 'triple'), which will match all or as standalone words and not as parts of words.
DEMO: http://jsfiddle.net/48E6M/
Related
First, I'm creating a library for JavaScript and I can not use jQuery. I'm trying to get the text content of an HTML element without the text contents of its children.
Both attributes innerText and textContent don't give me what needed, please help.
You can solve using DOM API as childNodes and nodeType.
var elChildNode = document.querySelector("#hello").childNodes;
var sChildTextSum = "";
elChildNode.forEach(function(value){
if(value.nodeType === Node.TEXT_NODE) {
console.log("Current textNode value is : ", value.nodeValue.trim());
sChildTextSum += value.nodeValue;
}
});
console.log("All text value of firstChild : ", sChildTextSum);
I created a sample code as above.
https://jsfiddle.net/nigayo/p7t9bdc3/
To get Author's Name from the following element, excluding <span>...:
<div class="details__instructor">
Author's Name<span ng-show="job_title">, Entrepreneur</span>
</div>
use childNodes[0]. For example:
document.querySelector('div.details__instructor').childNodes[0].textContent
Using only JavaScript (you specified you cannot use jQuery), and given that you have provided and know the id for the parent element:
document.getElementById('parent_element_id').childNodes[0].nodeValue;
You can also use .trim() to remove any trailing space characters left behind from the removal of any child element text:
document.getElementById('parent_element_id').childNodes[0].nodeValue.trim();
var mydiv = getElementByID("id");
function Get_text(element) {
var selected = element.cloneNode(true);
var text;
while (selected.firstChild) {
if (selected.firstChild.nodeType == 3) text = selected.firstChild.nodeValue;
selected.removeChild(selected.firstChild);
}
return text;
}
Get_text(mydiv);
I know many good solutions here exist, but none of them actually achieved what I needed (get the textContent of a single node, none of its children), so sharing this for future searchers.
var html = document.getElementsByTagName("*");
for (var i = 0; i < html.length; i++) {
var el = html[i];
for (var j = 0; j < el.children.length; j++) {
var child = el.children[j],
childTextContent = child.innerHTML;
// Remove all children tags, leaving only the actual text of the node.
childTextContent = childTextContent.replace(/\<.*\>.*\<\/.*\>/gmi, "");
// Also remove <img /> type tags.
childTextContent = childTextContent.replace(/\<.*\ \/\>/gmi, "");
console.log(childTextContent);
// Now you can do any type of text matching (regex) on the result.
}
});
This is sort of a continuation of an earlier question.
I have some html.
<h3>things that are red:</h3>
<ul>
<li>Red Apples</li>
<li>Red Meat</li>
<li>All Red Cars</li>
</ul>
I want to use javascript to wrap all of the text elements with a element
The result I am looking for.
<h3>things that are <span class="red">red</span>:</h3>
<ul>
<li><span class="red">Red</span> Apples</li>
<li><span class="red">Red</span> Meat</li>
<li>All <span class="red">Red</span> Cars</li>
</ul>
After a lot of thought I realized that I had to distinguish between text nodeTypes and Element NodeTypes while navigating the DOM. I used some of the feedback from my earlier question, and wrote this little script.
function walkTheDOM(node, func) {
func(node);
node = node.firstChild;
while (node) {
walkTheDOM(node, func);
node = node.nextSibling;
}
}
walkTheDOM(document.body, function (node) {
// Is it a Text node?
if (node.nodeType === 3) {
var text = node.data.trim();
// Does it have non white-space text content?
if (text.length > 0) {
node.data = text.replace(/(RED)/gi, '<span class="red">$1</span>');
}
}
});
This does pretty much what I want it to do, except the output is text rather than html. So my question is this, is there an easy way to fix this line
node.data = text.replace(/(RED)/gi, '<span class="red">$1</span>');
So that the output is html?
What you need to do to make this generic, as I have hinted in the comment, is to create a new element, put the text node into it, then replace the text node with the new element.
function wrapTextNode(textNode) {
var spanNode = document.createElement('span');
spanNode.setAttribute('class', 'red');
var newTextNode = document.createTextNode(textNode.textContent);
spanNode.appendChild(newTextNode);
textNode.parentNode.replaceChild(spanNode, textNode);
}
[].forEach.call(document.querySelectorAll('a'), function(el) {
var textNode = el.childNodes[0];
wrapTextNode(textNode);
});
EDIT: fiddle
DEMO
$(function() {
$('li a').html(function(i,html) {
return html.replace(/(RED)/gi, '<span class="red">$1</span>');
});
});
The answer from Amadan is perfect to manipulate (convert from textnode to element for css purposes) for instance some VAT-text-information in the cart-totals section on the cart page in the storefront-child-theme in woocommerce in wordpress. There is no other usual or better way of changing this little piece of textnode that lies within a div containing different textnodes and elementnodes. So i wanted to say thanks for this solution.
Of course, this only works if you use only one language.
var cart_totals = document.querySelector(".cart_totals .shop_table");
if( !!cart_totals ) {
for( var x = 0; x < cart_totals.childNodes.length; x++ ) {
if( cart_totals.childNodes[x].nodeType === 3 &&
cart_totals.childNodes[x].nodeValue.includes( 'inkl. 19 % MwSt.' ) ) {
var textNode = cart_totals.childNodes[x];
wrapTextNode( textNode ); /* see function from Amadan above */
}
}
}
I have some div ids that are generated dynamicly via php
<div id='a<?php echo $gid?>>
How can I access them in JavaScript? All these divs start with "A" followed by a number.
Is there some kind of search function
getElementById(a*)?
Thanks for any help
No generic JavaScript function for this (at least not something cross browser), but you can use the .getElementsByTagName and iterate the result:
var arrDivs = document.getElementsByTagName("div");
for (var i = 0; i < arrDivs.length; i++) {
var oDiv = arrDivs[i];
if (oDiv.id && oDiv.id.substr(0, 1) == "a") {
//found a matching div!
}
}
This is the most low level you can get so you won't have to worry about old browsers, new browsers or future browsers.
To wrap this into a neater function, you can have:
function GetElementsStartingWith(tagName, subString) {
var elements = document.getElementsByTagName(tagName);
var result = [];
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (element.id && element.id.substr(0, subString.length) == subString) {
result.push(element);
}
}
return result;
}
The usage example would be:
window.onload = function() {
var arrDivs = GetElementsStartingWith("div", "a");
for (var i = 0; i < arrDivs.length; i++) {
arrDivs[i].style.backgroundColor = "red";
}
};
Live test case.
In case you choose to use jQuery at some point (not worth for this thing alone) all the above code turns to single line:
$(document).ready(function() {
$('div[id^="a"]').css("background-color", "blue");
});
Updated fiddle, with jQuery.
No, you need a fixed id value for getElementById to work. However, there are other ways to search the DOM for elements (e.g. by CSS classes).
You can use querySelectorAll to get all divs that have an ID starting with a. Then check each one to see if it contains a number.
var aDivs = document.querySelectorAll('div[id^="a"]');
for(var index = 0, len = aDivs.length; index < len; index++){
var aDiv = aDivs[index];
if(aDiv.id.match(/a\d+/)){
// aDiv is a matching div
}
}
DEMO: http://jsfiddle.net/NTICompass/VaTMe/2/
Well, I question myself why you would need to select/get an element, that has a random ID. I would assume, you want to do something with every div that has a random ID (like arranging or resizing them).
In that case -> give your elements a class like "myGeneratedDivs" with the random ID (if you need it for something).
And then select all with javascript
var filteredResults=document.querySelectorAll(".myGeneratedDivs").filter(function(elem){
....
return true;
});
or use jQuery/Zepto/YourWeaponOfChoice
var filteredResults=$(".myGeneratedDivs").filter(function(index){
var elem=this;
....
return true;
});
If you plan to use jQuery, you can use following jQuery selectors
div[id^="a"]
or
$('div[id^="id"]').each(function(){
// your stuff here
});
You will have to target the parent div and when someone click on child div inside a parent div then you can catch the child div.
<div id="target">
<div id="tag1" >tag1</div>
<div id="tag1" >tag2</div>
<div id="tag1" >tag3</div>
</div>
$("#target").on("click", "div", function() {
var showid = $(this).attr('id');
alert(showid)
});
getElementById() will return the exact element specified. There are many javascript frameworks including jQuery that allow much more powerful selection capabilities. eg:
Select an element by id: $("#theId")
Select a group of elements by class: $(".class")
Select subelements: $("ul a.action")
For your specific problem you could easily construct the appropriate selector.
The tricky part is not selecting the elements here, but just selecting the text within. The only true jQuery that will give you back text contents is .contents(). So I'm getting the contents of every element not he page, and I want to pick out a word, such as "hashtag". Then append to it.
What am I doing wrong here:
<html>
<p>
The word hashtag is in this sentence.
</p>
</html>
jQuery:
$(function() {
$('*')
.contents()
.filter(function(){
return this.nodeType === 3;
})
.filter(function(){
return this.nodeValue.indexOf('hashtag') != -1;
})
.each(function(){
alert("It works!")
});
});
$('*') grabs every element
.contents() grabs the contents of every element
.filter(function(){ return this.noteType === 3; refines it down to the text contents of elements. (#3 node type is text)
return this.nodeValue.indexOf('hashtag') should grab the word "hashtag". Not sure if this is working.
!= -1; should prevent it from grabbing every single element in the HTML. Not sure about that one.
Why doesn't it work? I know I have anything appending tags yet, but can I select the word "hashtag" thanks!
If you want to do this for the whole page you can work on the HTML of the body element:
$(function() {
var regExp = new RegExp("\\b(" + "hashtag" + ")\\b", "gm");
var html = $('body').html();
$('body').html(html.replace(regExp, "<a href='#'>$1</a>"));
});
Keep in mind that this may be slow if your page is large. Also, all elements will be rewritten and thus loose their event handlers etc.
If you don't want this or want to restrict the replacement to certain elements, you can select and iterate over them:
$(function() {
var regExp = new RegExp("\\b(" + "hashtag" + ")\\b", "gm");
$('div, p, span').each(function() { // use your selector of choice here
var html = $(this).html();
$(this).html(html.replace(regExp, "<a href='#'>$1</a>"));
});
});
JS :
function replaceText() {
$("*").each(function() {
if($(this).children().length==0) {
$(this).html($(this).text().replace('hashtag', '<span style="color: red;">hashtag</span>'));
}
});
}
$(document).ready(replaceText);
$("html").ajaxStop(replaceText);
HTML :
<html>
<p>
The word hashtag is in this sentence.
</p>
</html>
Fiddle : http://jsfiddle.net/zCxsY/
Source : jQuery - Find and replace text, after body was loaded
This is done with span but will work with obviously
The clean variant would be this:
$(function() {
var searchTerm = 'hashtag';
$('body *').contents()
.filter(function () {
return this.nodeType == 3
&& this.nodeValue.indexOf(searchTerm) > -1;
})
.replaceWith(function () {
var i, l, $dummy = $("<span>"),
parts = this.nodeValue.split(searchTerm);
for (i=0, l=parts.length; i<l; i++) {
$dummy.append(document.createTextNode(parts[i]));
if (i < l - 1) {
$dummy.append( $("<a>", {href: "", text: searchTerm}) );
}
}
return $dummy.contents();
})
});
It splits the value of the text node at searchTerm and re-joins the parts as a sequence of either new text nodes or <a> elements. The nodes created this way replace the respective text node.
This way all text values keep their original meaning, which cannot be guaranteed when you call replace() on them and feed them to .html() (think of text that contains HTML special characters).
See jsFiddle: http://jsfiddle.net/Tomalak/rGcxw/
I don't know jQuery very much but I think you can't just say .indexOf('hashtag'), you have to iterate through the text itself. Let's say with substring. Probably there's an jQuery function that will do this for you, but that might be your problem for finding 'hashtag'.
Need to replace colons wherever they're found in specific elements with id's. This works but for some reason also replaces the styling attached to the elements:
$(document).ready(function(){
$("#element").each(function () { //for element
var s=$(this).text(); //get text
$(this).text(s.replace(/:/g, ' ')); //set text to the replaced version
});
});
I tried attaching a class to the element but it made no difference. How do I just remove the colons without affecting anything else?
Demo
I think you want to use the .html() method: http://api.jquery.com/html/
because according to this: http://api.jquery.com/text/
it calls the DOM method .createTextNode(), which replaces special characters with their HTML entity equivalents (such as < for <)
$(document).ready(function(){
$("#element").each(function () { //for element
var s=$(this).html(); //get text
$(this).html(s.replace(/:/g, ' ')); //set text to the replaced version
});
});
What is the HTML code in #element ?
If replacing the text in #element changes the style, it means that #element also contains some HTML tags (and the style is actually applied on those tags).
Try this:
$(document).ready(function() {
$("#element").each(function () {
(function trim_colons(el) {
for (var i = 0; i < el.childNodes.length; ++i) {
var c = el.childNodes[i];
if (c.nodeType == 1) trim_colons(c);
else if (c.nodeType == 3) c.nodeValue = c.nodeValue.replace(/:/g, ' ');
}
})(this);
});
});
This will correctly remove : characters, without changing the style.
Certainly you did'nt meant to have text in input types replaced ha!
For html elements other than input elements to fetch innerhtml you should use
var s=$(this).html();