How can I replace a text or number in a span element with javascript/jquery?
this is what i have tried but the console says "Cannot call method 'replace' of undefined" dont understand whats the problem, can someone point me in the right direction?
function changeNumber()
{
var element = document.getElementsByClassName("grade").innerHTML;
var x = element.replace('1','*');
document.getElementsByClassName("grade").innerHTML=x;
}
If it matters the span element i created dynamically in javascript...
document.getElementsByClassName("grade") returns a NodeList, it is not like getElementbyId, you need to loop it.
If you just have one
function changeNumber()
{
var element= document.getElementsByClassName("grade")[0];
var text = element.innerHTML;
var x = text.replace('1','*');
element.innerHTML=x;
}
If you have a set
function changeNumber()
{
var elements= document.getElementsByClassName("grade");
for (var i=0; i<elements.length; i++) {
var element = elements[i];
var text = element.innerHTML;
var x = text.replace('1','*');
element.innerHTML=x;
}
}
If you already have jQuery included in your page, and are comfortable with it's usage, try the following code:
function changeNumber()
{
$(".grade").each(function(){
var self = this
self.text(self.text().replace('1','*'))
});
}
Working demo: http://jsfiddle.net/pratik136/uUHv8/
While the posted answers are correct, and despite the fact that you've accepted an answer, I was intrigued by the possibility of creating a replace() function to work with a nodeList (or, strictly-speaking, an Object), so:
Object.prototype.replace = function (n, r) {
var textMethod = this[0] && this[0].textContent !== undefined;
for (var i = 0, len = this.length; i < len; i++) {
if (textMethod) {
this[i].textContent = this[i].textContent.replace(n, r);
} else {
this[i].innerText = this[i].innerText.replace(n, r);
}
}
return this;
};
document.getElementsByTagName('p').replace(/1/, '*');
JS Fiddle demo.
I can confirm this works in Chrome 25, Firefox 19 (also 14 and 18, hadn't updated this computer in a while) under Win XP. I can't test in IE, since it, and JS Fiddle, seem to be having issues.
It may, also, not be a good idea; but it seemed useful (and relatively interesting) at the point at which I put it together. Hopefully it may be of some use.
Related
Everytime I try to reproduce .each() jQuery function in vanilla JavaScript, I'm in trouble.
When I try to change this :
$("[data-lng]").each(function(){
var lng = $(this).data('lng');
$('#language').text(lng)
});
To this :
var elem = document.querySelectorAll("[data-lng]");
Array.prototype.forEach.call(elem, function(){
document.getElementById('language').write = elem.dataset.lng
});
Console returns elem.dataset is not defined
Plus, I'm dealing with data stuff so I'm not even sure if its legal to write this document.querySelectorAll("[data-lng]")
Thanks for your help !
PS : Here is an example of what I want to convert into vanilla JS :
https://jsfiddle.net/x93oLad8/4/
Its fairly trivial to swap your jsFiddle example out for vanilla JS. One 'gotcha' to be aware of is that IE has no support for NodeList.prototype.forEach() hence using a regular for loop instead. (See: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach)
var dictionary = {
'greet': {
'it': 'Ciao',
'en': 'Hello',
'fr': 'Salut',
}
};
var langs = ['it', 'en', 'fr'];
var current_lang_index = 0;
var current_lang = langs[current_lang_index];
window.change_lang = function() {
current_lang_index = ++current_lang_index % 3;
current_lang = langs[current_lang_index];
translate();
}
function translate() {
/* jQuery:
$("[data-translate]").each(function(){
var key = $(this).data('translate');
$(this).html(dictionary[key][current_lang] || "N/A");
});*/
/* vanilla */
var dt = document.querySelectorAll("[data-translate]");
//iterate over the NodeList:
for (i = 0; i < dt.length; ++i) {
var key = dt[i].getAttribute('data-translate');//get the key
dt[i].innerHTML = (dictionary[key][current_lang] || "N/A");//set the text
}
}
translate();
<div data-translate="greet"></div>
<button onclick="change_lang()">Change Language</button>
First of all, instead of using:
Array.prototype.forEach.call(elem, function()
You can just use
elem.forEach(function()
Secondly, callback function can accept arguments (3 of them to be specific):
el - current elem (which is the "this" you are looking for? :))
index - index of current elem in array
list - the nodelist you loop over
Usage:
elem.forEach(function(el, index, list){
console.log(el); //logs current element
});
Read more: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
#Edit: Since there was a big discussion in the comments about the first part, i feel obligated to link a thread on overriding default methods in JS: [].slice or Array.prototype.slice (a.k.a why elem.forEach might not work, just in case :))
List only rendered styles, not arbitrary ones that aren't applied
I've tried many things to get the styles applied to an element but have come up blank.
Please do not cite getComputedStyle as being a solution unless you can solve the junk returns issue.
The primary problem is that window.getComputedStyle(document.querySelector('ANY ELEMENT')).fill will return "rgb(0, 0, 0)", which is not the correct style in almost any instances, and has no apparent way to destinguish if its actually being applied or not.
The above example is not the only problem case; there are tons of rules returned by getComputedStyle which are wrong and will drastically change the look of the page if they are applied.
Static parsing is not an option as there are cases where the .css files are on another server with no cross-origin headers; which also hides styles usually found in document.styleSheets.
Is there any way to get a list of the applied styles and nothing else?
As requested this code will demonstrate the problem (on Chrome):
var all = document.getElementsByTagName('*');
for(var i in all)
if (all[i].style) all[i].style.cssText = window.getComputedStyle(all[i]).cssText;
EDIT: My answer has code which works on all browsers. I keep above to preserve comment thread.
Here are the version that don't need to check depth.
The problem in your code is the assign of inline style in the previous element will affect the getComputedStyle result of the next result. It mean the value of getComputedStyle is always changing in the loop. You can first store it in an array like this.
var all = document.getElementsByTagName('*');
tmpArr = []
for(var i in all) {
if (all[i].style) {
tmpArr[i] = window.getComputedStyle(all[i]).cssText;
}
}
for(var i in all) {
if (all[i].style) {
all[i].style.cssText = tmpArr[i]; ;
}
}
console.log("finish");
You can change tmpArr[i] = window.getComputedStyle(all[i]).cssText; to tmpArr[i] = window.getComputedStyle(all[i]).cssText + "-webkit-text-fill-color:#691099!important"; to test whether it work
It will be slow if you open the inspector since there are too much inline style, but it will solve the problem if all you need is just put the style to be inline style.
Partial Answer (Updated):
It is possible to get only the active styles by calling my function getRenderedStyles:
getRenderedStyles now bypasses active stylesheets for more accurate output.
function getRenderedStyles(element) {
var tmpele, tmpstyle, elestyle, varstyle, elecolor, eletag;
var styles = {};
var defstyle = {};
elestyle = window.getComputedStyle(element);
elecolor = elestyle.color;
eletag = element.tagName;
var frag = document.createDocumentFragment();
frag.appendChild(document.documentElement);
tmpele = document.appendChild(document.createElement(eletag));
tmpstyle = window.getComputedStyle(tmpele);
styles['color'] = elecolor===tmpstyle.color?undefined:elecolor;
tmpele.style.color = elecolor; // workaround for color propagation on other styles
for (var i in tmpstyle)
defstyle[i] = tmpstyle[i];
tmpele.remove();
document.appendChild(frag);
varstyle = element.style;
for (var i in varstyle) {
if ((((typeof varstyle[i])==="string"))&&(i!=="cssText")) {
if ((defstyle[i]!==elestyle[i]))
styles[i] = elestyle[i];
}
}
return styles;
}
Sadly there's a caviat as the browser still seemingly returns invalid styles in some cases. Often shifting the locations of elements.
To verify this you may run the following code, which takes into account parent/child inheritance, in an attempt to properly apply the current styles to the page:
function DOMDepth(element) {
var cur = element;
var deep = 0;
while(cur.parentNode)
deep++, cur = cur.parentNode;
return deep;
}
function getElementsByDepth() {
var all = document.getElementsByTagName('*');
var depth_map = {};
var deepest = 0;
for(var i in all) {
var depth = DOMDepth(all[i]);
deepest = depth>deepest?depth:deepest;
depth_map[depth] = depth_map[depth] || [];
depth_map[depth].push(all[i]);
}
depth_map['deepest'] = deepest;
return depth_map;
}
function inlineComputedStyles() {
var depth_map = getElementsByDepth();
for (var i = depth_map.deepest; i>0; i--) {
var elements = depth_map[i];
for (var j in elements) {
var styles = getRenderedStyles(elements[j]);
for (var k in styles) {
elements[j].style[k] = styles[k];
}
}
}
}
I have tested the preceeding and can confirm it does not suffer the color problems of the snippet in the question. Sadly I am uncertain as to why some elements still shift or if there's a way to fix it.
Special thanks to Kit Fung for pointing out the inheritance problem.
I'm still in the process of learning JavaScript. and I would like to complete the task using only JavaScript and no Jquery.
I have multiple div/images that I’m trying to manipulate using the z-index, and a button that randomize the images to come to the front.
I got the random image array to work but as you could see in image[1]…setting each changeZ index will be laborious. So I’m embarking on changing the class’s (as seen in image[0] so I could add current to the new image and send current to the background on the next go around and then removing the class attribute. I have got the element to work separate but having trouble putting it together in a array.
function changeZIndex(i,id) {
document.getElementById(id).style.zIndex=i;};
function changeClassZIndex(i,tagName){
document.getElementsByTagName("*").style.zIndex=i;};
function getImage(){
var whichImage=Math.floor(Math.random()*3);
var image=new Array()
var currentPhoto = div.current
image[0]=function() {
changeZIndex(5,"scene1");
changeClassZIndex(-5,"current");
currentPhoto.removeClass('current')
document.getElementById("scene1").className += "current"; };
image[1]=function() {
changeZIndex(5,"scene2");
changeZIndex(-5,"scene1");
changeZIndex(-5,"scene3");
changeZIndex(-5,"scene");
};
image[2]=function() {
changeZIndex(5,"scene3");
changeZIndex(-5,"scene");
changeZIndex(-5,"scene2");
changeZIndex(-5,"scene1");
};
image[whichImage].apply(undefined);};
It's because document.getElementsByTagName() returns an array of elements, which you can't do operations like that on. Instead, you need to enumerate through them and do the operations individually.
Here's a working jsfiddle which shows exactly how to do it: jsfiddle
As a side note: if there's one thing a lot of web programming will teach you, its this:
Dont ever, ever, rule out jQuery as an option.
JQuery is your best friend, and the use of it in this situation would cut down your lines of code by well over half.
Firstly, I believe your problem is probably in changeClassZIndex(i,tagName)
which should probably look something like this:
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
}
}
function changeClassZIndex(z,className) {
var e = document.getElementsByClassName(className);
for(var i = 0; i < e.length; i++) {
e[i].style.zIndex = z;
}
};
I am defining the getElementsByClassName function if it does not exist because some browsers may not support it.
I may suggest taking a different approach to your problem however:
var images = new Array("scene1", "scene2", "scene3");
var currentPhoto = div.current
var whichImage = Math.floor(Math.random()*images.length);
// change all images to the background
for(var i = 0; i < images.length; i++)
{
changeZIndex(-5, images[i]);
}
// change the one you want to the top
changeZIndex(5, images[whichImage]);
That way you do not have to write functions for each image, and adding images is as easy as adding to the array.
I want to replace the contents within a html element so I'm using the following function for that:
function ReplaceContentInContainer(id,content) {
var container = document.getElementById(id);
container.innerHTML = content;
}
ReplaceContentInContainer('box','This is the replacement text');
<div id='box'></div>
The above works great but the problem is I have more than one html element on a page that I want to replace the contents of. So I can't use ids but classes instead. I have been told that javascript does not support any type of inbuilt get element by class function. So how can the above code be revised to make it work with classes instead of ids?
P.S. I don't want to use jQuery for this.
This code should work in all browsers.
function replaceContentInContainer(matchClass, content) {
var elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if((' ' + elems[i].className + ' ').indexOf(' ' + matchClass + ' ')
> -1) {
elems[i].innerHTML = content;
}
}
}
The way it works is by looping through all of the elements in the document, and searching their class list for matchClass. If a match is found, the contents is replaced.
jsFiddle Example, using Vanilla JS (i.e. no framework)
Of course, all modern browsers now support the following simpler way:
var elements = document.getElementsByClassName('someClass');
but be warned it doesn't work with IE8 or before. See http://caniuse.com/getelementsbyclassname
Also, not all browsers will return a pure NodeList like they're supposed to.
You're probably still better off using your favorite cross-browser library.
document.querySelectorAll(".your_class_name_here");
That will work in "modern" browsers that implement that method (IE8+).
function ReplaceContentInContainer(selector, content) {
var nodeList = document.querySelectorAll(selector);
for (var i = 0, length = nodeList.length; i < length; i++) {
nodeList[i].innerHTML = content;
}
}
ReplaceContentInContainer(".theclass", "HELLO WORLD");
If you want to provide support for older browsers, you could load a stand-alone selector engine like Sizzle (4KB mini+gzip) or Peppy (10K mini) and fall back to it if the native querySelector method is not found.
Is it overkill to load a selector engine just so you can get elements with a certain class? Probably. However, the scripts aren't all that big and you will may find the selector engine useful in many other places in your script.
A Simple and an easy way
var cusid_ele = document.getElementsByClassName('custid');
for (var i = 0; i < cusid_ele.length; ++i) {
var item = cusid_ele[i];
item.innerHTML = 'this is value';
}
I'm surprised there are no answers using Regular Expressions. This is pretty much Andrew's answer, using RegExp.test instead of String.indexOf, since it seems to perform better for multiple operations, according to jsPerf tests.
It also seems to be supported on IE6.
function replaceContentInContainer(matchClass, content) {
var re = new RegExp("(?:^|\\s)" + matchClass + "(?!\\S)"),
elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if (re.test(elems[i].className)) {
elems[i].innerHTML = content;
}
}
}
replaceContentInContainer("box", "This is the replacement text.");
If you look for the same class(es) frequently, you can further improve it by storing the (precompiled) regular expressions elsewhere, and passing them directly to the function, instead of a string.
function replaceContentInContainer(reClass, content) {
var elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if (reClass.test(elems[i].className)) {
elems[i].innerHTML = content;
}
}
}
var reBox = /(?:^|\s)box(?!\S)/;
replaceContentInContainer(reBox, "This is the replacement text.");
This should work in pretty much any browser...
function getByClass (className, parent) {
parent || (parent=document);
var descendants=parent.getElementsByTagName('*'), i=-1, e, result=[];
while (e=descendants[++i]) {
((' '+(e['class']||e.className)+' ').indexOf(' '+className+' ') > -1) && result.push(e);
}
return result;
}
You should be able to use it like this:
function replaceInClass (className, content) {
var nodes = getByClass(className), i=-1, node;
while (node=nodes[++i]) node.innerHTML = content;
}
var elems = document.querySelectorAll('.one');
for (var i = 0; i < elems.length; i++) {
elems[i].innerHTML = 'content';
};
I assume this was not a valid option when this was originally asked, but you can now use document.getElementsByClassName('');. For example:
var elements = document.getElementsByClassName(names); // or:
var elements = rootElement.getElementsByClassName(names);
See the MDN documentation for more.
There are 3 different ways to get elements by class in javascript. But here for your query as you have multiple elements with the same class names you can use 2 methods:
getElementsByClassName Method - It returns all the elements with the specified class present in the document or within the parent element which called it.
function ReplaceContentInContainer(className, content) {
var containers = document.getElementsByClassName(className);
for (let i = 0; i < containers.length; i++) {
containers[i].innerHTML = content;
}
}
ReplaceContentInContainer('box', 'This is the replacement text');
<div class='box'></div>
querySelectorAll Method - It select element on the basic of CSS selectors. Pass your CSS class to it with a dot and it will return all the element having specified class as an array-like object.
function ReplaceContentInContainer(className, content) {
var containers = document.querySelectorAll(`.${className}`);
for (let i = 0; i < containers.length; i++) {
containers[i].innerHTML = content;
}
}
ReplaceContentInContainer('box', 'This is the replacement text');
<div class='box'></div>
I think something like:
function ReplaceContentInContainer(klass,content) {
var elems = document.getElementsByTagName('*');
for (i in elems){
if(elems[i].getAttribute('class') == klass || elems[i].getAttribute('className') == klass){
elems[i].innerHTML = content;
}
}
}
would work
jQuery handles this easy.
let element = $(.myclass);
element.html("Some string");
It changes all the .myclass elements to that text.
When some elements lack ID, I use jQuery like this:
$(document).ready(function()
{
$('.myclass').attr('id', 'myid');
});
This might be a strange solution, but maybe someone find it useful.
It's probably something really simple, but I'm just learning.
There's a page with 3 blockquote tags on it, and I'd need to get the innerHTML of the one containing a certain string. I don't know how to search/match a string and get the innerHTML of the tag containing the matched result.
Any help would be appreciated!
var searchString = 'The stuff in innerHTML';
var elements = document.getElementsByTagName('blockquote')
for (var i = 0; i < elements.length; i++) {
if (elements[i].innerHTML.indexOf(searchString) !== -1) {
alert('Match');
break;
}
}
:)
Btw there would be a much nicer method if you'd be using Prorotype JS (which is much better than jQuery btw):
var el = $$('blockquote').find(function(el) {
return el.innerHTML.indexOf('The string you are looking for.') !== -1;
});
You could of course also use regular expressions to find the string, which might be more useful (use el.match() for that).
If you need to search through every <blockquote> on the page, try this:
function findBlockquoteContainingHtml(matchString) {
var blockquoteElements = document.getElementsByTagName('BLOCKQUOTE');
var i;
for (i = 0; i < blockquoteElements.length; i++) {
if (blockquoteElements[i].innerHTML.indexOf(matchString) >= 0) {
return blockquoteElements[i].innerHTML;
}
}
return null;
}
Assign an id to the blockquote elements then you can get the innerHTML like this:
HTML:
<blockquote id="bq1">Foo</blockquote>
JS:
var quote1 = document.getElementById('bq1').innerHTML;
Be careful using innerHTML to search for text within a tag, as that may also search for text in attributes or tags as well.
You can find all blockquote elements using:
var elems = document.getElementsByTagName("blockquote")
You can then look through their innerHTML, but I would recommend instead looking through their textContent/innerText (sadly, this is not standardized across browser, it seems):
for (i in elems) {
var text = elems[i].textContent || elems[i].innerText;
if (text.match(/foo/)) {
alert(elems[i].innerHTML);
}
}