jQuery replaceWith not working without DOM - javascript

I am trying to do some element manipulation on a Node.js server where I need to take a string of HTML, then replace some of the nodes with other node types. This was working fine when I was doing it with a DOM but as soon as I don't have a DOM it does not work.
In a very simple example, I want to do something like this... where I find all the div elements and replace with spans.
const html = '<html><div>hello</div><div>hello</div></html>';
const obj = $(html);
const filter = $(obj).find('div');
for (let j = filter.length; j >= 0; j--) {
$(filter[j]).replaceWith("<span>goodbye</span>");
}
console.log(obj);
I can't just do a find and replace on the string as I don't want all elements I am doing a filter based on various things before I do this.
It is not working saying that the node is not an element. Is there a way I can do this? I have also tried using JSDOM to do this but again, no luck.
I want the console here to show the HTML element with two spans rather than two divs, I have tried adding a jsfiddle for this however I am getting a different error on here too, if anyone can help it would be appreciated.
http://jsfiddle.net/vkn285a1/1/
** UPDATE **
From the answer below, I have updated but I am now getting my desired result, thank you.. I had to change to use SVG which is what I am actually parsing and it worked a treat
const html = "<svg><g><text>hello</text><text>hello</text></g></svg>";
const obj = $.parseHTML(html);
const filter = $(obj).find("text");
for (let j = filter.length; j >= 0; j--) {
$(filter[j]).replaceWith("<span>goodbye</span>");
}

Your issue is following:
const obj = $(html);
this obj is NULL.
You have to use parseHTML function to get object from string as following.
const html = '<html><div>hello</div><div>hello</div></html>';
const obj = $.parseHTML(html);
Then obj will be an array of divs in html tag of string.
After that, you can try anything for those objects that are not NULL.

Related

Trying to print all the elements of a page to the console

I'm trying to print all the h3 of my website into a list within the console but its not working? I've even tried it on a random online site to check if it would work and it doesn't make a difference... The irony is its the same code i've used before to do it on my website but It's not working
Heres what im running in the console
for(i = 0; i < 300; i++) {console.log(document.getElementsByTagName("H3")
[i].innerHTML)};
Heres a sample of what my website html would be...
<h3>Hello</h3>
<h3>There</h3>
<h3>My</h3>
<h3>Fried</h3>
What Im trying to get to print to the console...
Hello
There
My
Friend
I've tried adjusting the upper limit of 300, I could do i.e document.getElementsByTagName["H3"].arrayLength or whatever and store that in a value as upper limit but thats besides the point. Its not working...
You are querying the DOM on each iteration instead of getting all elements, and then iterating them:
const elements = document.getElementsByTagName("H3")
for(i = 0; i < elements.length; i++) {console.log(elements[i].innerHTML)}
<h3>Hello</h3>
<h3>There</h3>
<h3>My</h3>
<h3>Fried</h3>
You can also use document.querySelectorAll() and convert the NodesList to an array using Array.from():
const elements = document.querySelectorAll('h3')
const arr = Array.from(elements, el => el.innerHTML)
console.log(arr.join(' '))
<h3>Hello</h3>
<h3>There</h3>
<h3>My</h3>
<h3>Fried</h3>

Setting data info on dynamically created html

I have a JSON response from a server, which returns me a array with 32 objects (in this case). Something like this:
[{object1},{ object2},{ object3}, etc].
Each object have some info that I use to populate an html template. For that, I just use a simple loop:
for(var i = 0; i < api_empresaListar.length; i++)
{
var item = api_empresaListar[i];
var htmls;
htmls = $('...lots of html code');
...
Then it’s just a simple matter of finding/changing the values, and append items on the DOM. Everything works fine. BUT, for some next parts of the code, I would like to access all the info from the object I used to build the html elements (I just show part of the info). So, after searching a lot, I tried to use data, like this:
var tp = htmls.find(".rl_grupo"); // the main div of each html element created in the loop
$(tp).data('key', api_empresaListar[i]); // here, I expected to just insert the object data in each created item.
But when I try it in the console, I got the object info as expected, but always from the last element in the array. Why is that happening? I believe it might be something stupid, but I can’t figure it out.
So, any ideas on how to solve this, or another method to make this work is appreciated. I made it work by setting some "display:none" placeholder html tags and populate those with the info I need later, but looks like a poor solution...
You should not set your htmls variable in the loop. I think that you crush its content every turn, that's why you only have the last item. You should do something like this:
var htmls = $('<div></div>');
for(var i = 0; i < api_empresaListar.length; i++) {
htmls.append($('...lots of html code'));
}
How about setting an index number on each element inside of your html creating code, then iterating over the $('.rl_grupo') elements, like this?
$('.rl_grupo').each(function(){
var index = $(this).data('index');
var currentData = api_empresaListar[index];
$(this).data('key', currentData);
})

jQuery - text() method?

Being fairly new to jquery and javascript I can't seem to understand how the .text() method really works. I read through the jQuery documentation but still can't figure it out.
for (var i=0; i < arrayLength; i++){
var currentElement = $(".artist")[i];
var currentArtist = currentElement.text;
console.log(currentElement);
console.log(currentArtist);
}
currentArtist returns "undefined" in the console. It works fine on the $(".artist") alone, but not when I use the [i] or anything additional for that matter. What am I missing here? How else could I grab a text value inside a selector?
By using the [] operator on jQuery object you're accessing the raw element node that was found by jQuery. This raw element doesn't have the jQuery methods anymore, nor a text property.
If you want to get single element from jQuery object and keep the jQuery wrapper, use eq method.
var artistElement = $(".artist").eq(i);
artistElement.text(); // gets the text content of the element
The code you've posted is also not very optimized. For instance, with every loop iteration you're searching the document over and over again for elements with class artist. Better to cache that search result in a variable before performing the loop. And if the loop iterates over all .artist elements, you can use jQuery's each method.
$(".artist").each(function () {
var artist = $(this); // this poits to the raw element thus wrapping into jQuery object
console.log(artist.text());
});
var currentArtist = currentElement.text;
Should be:
var currentArtist = currentElement.text();
You should use a each():
$(".artist").each(function(i,val){
var currentArtist = $(val).text();
console.log(val);
console.log(currentArtist);
});
$(".artist") produce a jQuery object that could be like this:
[div, div, div, div, prevObject: jQuery.fn.jQuery.init, context: document, selector: ".artist"...]
So the result of $(".artist")[i] is a HTMLElement and do not have a text method, that's why you're getting undefined
Also text() is a function and may be followed with ()
But if you want to keep the for loop you can do
for (var i=0; i < arrayLength; i++){
var currentElement = $(".artist")[i];
var currentArtist = $(currentElement).text();
console.log(currentElement);
console.log(currentArtist);
}
.text() shows the text of an html element or set of html elements that would be visible to the user.

Prepend some innerHTML to a div in Native Javascript

Please bear with me on this question; I have only recently started coding in Javascript and for this reason I would like a strong foundation before breaking into jQuery.
I have the following Javascript code:
var app = {
text: document.getElementById('text'),
output: document.getElementById('output'),
createDiv: document.createElement('div')
};
function postData(){
app.output[0].appendChild(app.createDiv.firstChild);
app.createDiv.classname = 'text';
document.getElementsByClassName('username').innerHTML += app.text.value;
}
onClick I want the value of app.text to print (using innerHTML) ABOVE the output div. Any ideas or questions? Sorry if I am being vague or not making sense, I have been staring at this for 4 hours now and am probably just burned out!
You'll have to create a text node and insert it before each element in the NodeList returned by document.getElementsByClassName:
var node = document.createTextNode(app.text.value);
var elements = document.getElementsByClassName('username');
for (var i = 0; i < elements.length; i++) {
var elem = elements[i];
elem.parentNode.insertBefore(node.cloneNode(), elem)
}
And just to tempt you with the jQuery version:
$('.username').before(app.text.value);
I'm not sure what you're asking, but I see the following problems with your code:
app.output[0]: there should be no [0], app.output is already an element (you got it by id). So use app.output.appendChild(app.createDiv.firstChild);. Still, this makes no sense; as Barmar said, you just created that div, so it doesn't have any children at that point.
app.createDiv.classname: should be className
document.getElementsByClassName('username').innerHTML: this returns multiple elements, maybe you want document.getElementsByClassName('username')[0].innerHTML?

Why doesn't this javascript work assign .cells[] properly?

Why doesn't this work?
var row = document.getElementById(currentRow);
var otherRow = document.getElementById(targetRow);
row.cells[0] = otherRow.cells[0];
This works with
row.cells[0].innerHTML = otherRow.cells[0].innerHTML;
However, there are attributes attached to the cell which I also want to move over without having to manually recreate them.
Solution (Note: more is being done in my actual implementation, but this is the framework):
for (var i = 0; i < 4; i++) {
var copyTo = row.cells[i];
var copyFrom = otherRow.cells[i].cloneNode(true);
copyTo.parentNode.replaceChild(copyFrom, copyTo);
}
You should be able to use cloneNode() to actually clone the node and its attributes.
Each entry in cells refers to a DOMElement. When you typed row.cells[0] = otherRow.cells[0], you are saying that you want row.cell[0] to reference the same DOMElement as otherRow.cells[0].
I'm guessing you want row.cells[0] to have the same text or HTML as otherRow.cells[0]; in which case, the second code snippet will do just that, since you are actually modifying the DOMElement, and not just changing which DOMElement you are referencing.

Categories

Resources