I am using Javascript/socket.io to display a chat message. I am trying to mirror the structure/classes that already exist in my HTML file:
<li>
<span id="messageUsername">{{message.user}}</span>
<p id="messageViewContent">{{message.content}}</p>
</li>
My javascript is as follows:
const li = document.createElement('li');
const spanUser = document.createElement('span');
const p = document.createElement('p');
spanUser.innerHTML = `${data.messageUser}`
spanUser.classList.add("messageUsername")
p.innerHTML = `${data.messageContent}`;
p.classList.add("messageViewContent");
li.innerHTML = p + spanUser;
document.querySelector('#messageLoop').append(li);
I also tried the following: li.innerHTML = p, spanUser; and li.append(p), neither worked. With my current code, instead of display a message it is displaying: [object HTMLParagraphElement]
What am I doing wrong here? It seems so simple but I just can't seem to get the right syntax. Thanks in advance.
You're trying to concatenate DOM elements, what you really want is append them to the previously created li element.
Remove this li.innerHTML = p + spanUser;
And append the elements to li element.
li.append(spanUser);
li.append(p);
Related
I am looking to replace an element in the DOM.
For example, there is an <a> element that I want to replace with a <span> instead.
How would I go and do that?
by using replaceChild():
<html>
<head>
</head>
<body>
<div>
<a id="myAnchor" href="http://www.stackoverflow.com">StackOverflow</a>
</div>
<script type="text/JavaScript">
var myAnchor = document.getElementById("myAnchor");
var mySpan = document.createElement("span");
mySpan.innerHTML = "replaced anchor!";
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
</script>
</body>
</html>
A.replaceWith(span) - No parent needed
Generic form:
target.replaceWith(element)
Way better/cleaner than the previous method.
For your use case:
A.replaceWith(span)
Advanced usage
You can pass multiple values (or use spread operator ...).
Any string value will be added as a text element.
Examples:
// Initially [child1, target, child3]
target.replaceWith(span, "foo") // [child1, span, "foo", child3]
const list = ["bar", span]
target.replaceWith(...list, "fizz") // [child1, "bar", span, "fizz", child3]
Safely handling null target
If your target has a chance to be null, you can consider using the newish ?. optional chaining operator. Nothing will happen if target doesn't exist. Read more here.
target?.replaceWith?.(element)
Related DOM methods
Read More - child.before and child.after
Read More - parent.prepend and parent.append
Mozilla Docs
Supported Browsers - 97% Nov '22
var a = A.parentNode.replaceChild(document.createElement("span"), A);
a is the replaced A element.
This question is very old, but I found myself studying for a Microsoft Certification, and in the study book it was suggested to use:
oldElement.replaceNode(newElement)
I looked it up and it seems to only be supported in IE. Doh..
I thought I'd just add it here as a funny side note ;)
I had a similar issue and found this thread. Replace didn't work for me, and going by the parent was difficult for my situation. Inner Html replaced the children, which wasn't what I wanted either. Using outerHTML got the job done. Hope this helps someone else!
currEl = <div>hello</div>
newElem = <span>Goodbye</span>
currEl.outerHTML = newElem
# currEl = <span>Goodbye</span>
You can replace an HTML Element or Node using Node.replaceWith(newNode).
This example should keep all attributes and childs from origin node:
const links = document.querySelectorAll('a')
links.forEach(link => {
const replacement = document.createElement('span')
// copy attributes
for (let i = 0; i < link.attributes.length; i++) {
const attr = link.attributes[i]
replacement.setAttribute(attr.name, attr.value)
}
// copy content
replacement.innerHTML = link.innerHTML
// or you can use appendChild instead
// link.childNodes.forEach(node => replacement.appendChild(node))
link.replaceWith(replacement)
})
If you have these elements:
Link 1
Link 2
Link 3
Link 4
After running above codes, you will end up with these elements:
<span href="#link-1">Link 1</span>
<span href="#link-2">Link 2</span>
<span href="#link-3">Link 3</span>
<span href="#link-4">Link 4</span>
You can use replaceChild on the parent of the target element after creating your new element (createElement):
const newElement = document.createElement(/*...*/);
const target = document.getElementById("my-table");
target.parentNode.replaceChild(newElement, target);
If your starting point for the new element is HTML, you can use insertAdjacentHTML and then removeChild on the parent (or remove on the element itself, in modern environments):
const target = document.getElementById("my-table");
target.insertAdjacentHTML("afterend", theHTMLForTheNewElement);
target.parentNode.removeChild(target); // Or: `target.remove()`
Best way to do it. No parents need. Just use Element.outerHTML = template;
// Get the current element
var currentNode = document.querySelector('#greeting');
// Replace the element
currentNode.outerHTML =
'<div id="salutations">' +
'<h1>Hi, universe!</h1>' +
'<p>The sun is always shining!</p>' +
'</div>';
Example for replacing LI elements
function (element) {
let li = element.parentElement;
let ul = li.parentNode;
if (li.nextSibling.nodeName === 'LI') {
let li_replaced = ul.replaceChild(li, li.nextSibling);
ul.insertBefore(li_replaced, li);
}
}
Given the already proposed options the easiest solution without finding a parent:
var parent = document.createElement("div");
var child = parent.appendChild(document.createElement("a"));
var span = document.createElement("span");
// for IE
if("replaceNode" in child)
child.replaceNode(span);
// for other browsers
if("replaceWith" in child)
child.replaceWith(span);
console.log(parent.outerHTML);
I have a list with people's data inside it has a li element with 3 p tags inside, one for name, one for address and one for email.
I filled this list manually but due to some changes to my code I had to rewrite this so the html would be made with javascript.
My code looked like this
<p class="adres">#logopedist.Adres</p>
<p class="email">#logopedist.Email</p>
<p class="mobiel">#logopedist.Mobiel</p>
I rewrote this to build the html using javascript. This looks something like this.
var li = document.createElement('li');
li.className = "lijst";
li.id = "lijst";
li.onclick = "ficheVullen(this)";
p.className = "naam";
p.innerHTML = objLogos.Naam[i];
li.appendChild(p);
p.className = "adres";
p.innerHTML = objLogos.Adres[i];
li.appendChild(p);
var p = document.createElement('p');
p.className = "mobiel";
p.innerHTML = objLogos.Mobiel[i];
li.appendChild(p);
My list generates properly. But in my old code I had this at the start of the list.
<li class="lijst" onclick="ficheVullen(this)">
Whenever you would click an li element it would fill a div with the info from the p tags inside that li, so it would fill the div with name, address, mobile,etc
I cannot seem to get this function to work anymore. It only works on the very first LI element and only works for the name. Even though my code is the same and I append classes to the tags like it had in my old code.
The function looks like this:
function ficheVullen() {
FicheNaam = document.getElementById("FicheNaam");
FicheAdres = document.getElementById("FicheAdres");
FicheGSM = document.getElementById("FicheGSM");
FicheNaam.innerHTML = this.querySelector('.naam').textContent;
FicheGSM.innerHTML = this.querySelector('.mobiel').textContent;
FicheAdres.innerHTML = this.querySelector('.adres').textContent;
I get this error now. Cannot read property 'textContent' of null
I call this function here:
window.onload = function() {
changePage(1);
document.getElementById("lijst").addEventListener("click", ficheVullen);
};
The changepage function is part of my pagination where I use javascript to build the list.
When I move the eventlistener out of this I get this error: Cannot read property 'addEventListener' of null.
I hope this gives enough context
You have to use setAttribute to set id.
elm.setAttribute("id", "uniqueId");
Your case : li.setAttribute("id", "lijst")
li.id = "lijst"; will add "id" to object not as attribute
const parent = document.getElementById("container")
let elm = document.createElement("p")
elm.setAttribute("id", "pElm")
elm.innerText = "p tag"
parent.append(elm)
document.getElementById("pElm").style.background = "red"
<div id="container"></div>
I am new with js and playing with replace method.
I have had no problems when replacing string for another string etc., but when im trying to do same with tags nothing happens..
Im trying to replace every tags for -tags. My function is below:
function bonus() {
var list = document.getElementsByTagName('li');
for (var i = 0; i < list.length; i++) {
newList = document.getElementsByTagName('li')[i].innerHTML;
newList = newList.replace('<li>', '<strong>');
newList = newList.replace('</li>', '</strong>');
document.getElementsByTagName('li')[i].innerHTML = (newList);
//console.log(newList);
}
}
function bonus(){
var list=document.getElementsByTagName('li');
var len = list.length;
for(var i=len-1; i>-1; i--){
var tmpItem = list[i]
newList = tmpItem.outerHTML;
newList = newList.replace('<li>','<strong>');
newList = newList.replace('</li>','</strong>');
tmpItem.outerHTML = newList;
}
}
I thought you might change your code like above, and there was still much space to optimize your code. go ahead <( ̄︶ ̄)>
First of all you should never replace a list-item with another element like that. A list item must always be a child of an ul or ol elelment, and ul and ol elements should not have any other immediate child that isn't a li.
However, this doesn't work because the li is an html element and not a text string and the inner HTML of an html elemnt doesn't contain the tag itself. It may contain children and those children's tags are part of the innerHTML, everything inside the element/tag itself is the innerHTML.
An example to clarify:
<ul>
<li>one<strong>second one</strong></li>
<li>two<strong>second two</strong></li>
<li>three<strong>second three</strong></li>
<li>four</li>
</ul>
Looping through all list items accessing elements as you've describe
for(var i=0; i<list.length;i++) {
console.log("==>> " + document.getElementsByTagName("li")[i].innerHTML);
}
Will output the following to the console:
==>> one<strong>second one</strong>
==>> two<strong>second two</strong>
==>> three<strong>second three</strong>
==>> four
If you want to make all li elements strong they should be nested as this:
<li><strong>Some text</strong></li>
To Achieve this one way to do it would be:
var list = document.getElementsByTagName("li");
for(var i=0; i<list.length; i++) {
var listItem = list[i];
listItem.innerHTML = "<strong>" + listItem.innerHTML + "</strong>";
}
If you want to convert all li elements to strong elements you must first remove them from the list...
Thanks alot for all of you. I knew that i can't change li for strong in real world, but i just tried to figure out if its possible to do so with simple loop.
My example html is full of lists, so thats why i used li instead of h2 to h3 or something like that. Outer html was new thing for me, and solution for this one. However Kim Annikas answer helped me with other question about modifying lists: I did this:
function replace(){
var list=document.getElementsByTagName('li');
for(var i=0;i<list.length;i++){
newText="<strong>Replaced!</strong>";
var listItem=list[i];
listItem.style.color="red";
listItem.innerHTML=newText;
}
}
..and now it seems that i have learnt how to modify tags as well as text inside of it ;)
I have 3 inputs that are nestled inside a span tag (I'm using span and not li because I have many li's in my code). I have a javascript function that appends each span tag (which includes the 3 inputs). I need each input to have a specific id name. Not sure how to do this, I'm learning javascript right now so forgive me for I'm a noob.
In my function I have the appendchild working for the span tag. At the bottom of the code I have a for loop that I wrote to append an ul/li and that name works. But I can't get that same functionality to work for the span tags.
How can I append child and each time I appendchild that the inputs get a new id name?
Here is my code so far:
function budgetList(){
var elmnt = document.getElementsByTagName("SPAN")[0];
var cln = elmnt.cloneNode(true);
var budgetListing = document.getElementById("budget-listing");
var append = budgetListing.appendChild(cln);
var expenseName = document.getElementById('expenseName');
var expectedExpense = document.getElementById('expectedExpense');
var actualExpense = document.getElementById('actualExpense');
var ul = document.createElement("ul");
document.body.appendChild(li);
for(var i = 0; i <= 0; i++){
var li = document.createElement("li");
li.className = "budget-list" + i;
var a = document.createElement("a");
a.innerHTML = "<input type='text'>";
// a.innerHTML = "Subfile " + i;
var att = document.createAttribute("class");
att.value = "budgeting" + i;
li.appendChild(a);
ul.appendChild(li);
}
}
Here is the html
<button onclick="budgetList()">Add New Row</button>
<input type="button" value="save" onclick="save()" />
<ul id="budget-listing">
<span>
<input type="text" id="expenseName">
<input type="text" id="expectedExpense">
<input type="text" id="actualExpense">
</span>
</ul>
A few things...
1) <ul> stands for Unordered List and <ul> elements expect their children to be <li> elements (which you can remember as List Item). So, while some browsers may be forgiving of you appending spans to your <ul> tag, it's not considered good practice. And is technically a violation of the standard
2) Your loop will only run exactly once. You'll see it's starting with variable i initialized at 0 and will only run as long as i<=0 which will only ever be true on the first iteration because afterwards you increment (i++) which means the second time through i will equal 1 and 1 is NOT less than or equal to 0. So, in this case there's no need to use a loop at all.
3) Your code is a little disjointed from what you requested and what the page context is suggesting. It appears to me, when the user clicks the button you want to duplicate the span with 3 inputs. If this is indeed the case, then I offer the following solution...
function budgetList(){
// You get the span that will serve as a template, good
var elmnt = document.getElementsByTagName("SPAN")[0];
// you clone it, good
var cln = elmnt.cloneNode(true);
//next we want to modify the IDs of the child spans.
// A good way to do this is to use a unique number that will change with every step
// There a few ways to get a unique number each time
// I propose taking the number of span groups
var budgetListing = document.getElementById("budget-listing");
var uniqueNumber = budgetListing.childNodes.length;
// Now we update all the ids using the unique number
cln.getElementsByTagName('INPUT')[0].setAttribute('id', "expenseName_"+uniqueNumber);
cln.getElementsByTagName('INPUT')[1].setAttribute('id', "expectedExpense_"+uniqueNumber);
cln.getElementsByTagName('INPUT')[2].setAttribute('id', "actualExpense_"+uniqueNumber);
// and write our new span group into the container
budgetListing.appendChild(cln);
}
Let me know if I made any incorrect assumptions or if this is close to what you're requesting. JavaScript and its interaction with HTML can be confusing at first, but stick with it!
EDIT: Didn't realize getElementById wasn't a function... Replaced with getElementsByTagName
I'm trying to insert a #HTML.ActionLink element inside a li element using the following code:
var ul = document.getElementById('container');
var enlace = '#Html.ActionLink("Details", "Details", "Elements", new { id = "5" }, null)';
var li = document.createElement('li');
li.appendChild(document.createTextNode('My title'));
li.appendChild(document.createElement('br'));
///////////////////////////////////////////////
li.appendChild(document.createElement(enlace));
///////////////////////////////////////////////
ul.appendChild(li);
Is it possible?
You're passing an entire HTML element to document.createElement(), which expects only a tag name. Essentially, you're doing this:
document.createElement('some text')
whereas the function works like this:
document.createElement('a');
You can probably fix this by separating the creation of the element from the setting of the element's HTML to your custom server-generated HTML. Replacing just the code surrounded by the comments, it might look like this:
///////////////////////////////////////////////
var enlaceElement = document.createElement('a');
enlaceElement.innerHTML = enlace;
li.appendChild(enlaceElement);
///////////////////////////////////////////////
I have a full demo here.