Dynamically add li to ul javascript - javascript

I have an array of names and I want to show them on my page.
I created an empty ul in my html
<ul id="friendsList">
</ul>
And now I want to add the names to this ol but I doesn't work
for (var i = 0; i < names.length; i++) {
var name = names[i];
var li = document.createElement('li', name);
li.parentElement('friendsList');
}
Error:
Exception was thrown by user callback. TypeError: li.parentElement is not a function

You have to append your li to ul. This document.createElement('li', name); won't work.
Syntax
document.createElement(tagName[, options]);
tagName:
A string that specifies the type of element to be created.
options (Optional):
An optional ElementCreationOptions object containing a single property named is, whose value is the tag name for a custom element previously defined using customElements.define().
document.createElement() documentation
var names = ['John', 'Jane'];
var ul = document.getElementById("friendsList");
for (var i = 0; i < names.length; i++) {
var name = names[i];
var li = document.createElement('li');
li.appendChild(document.createTextNode(name));
ul.appendChild(li);
}
<ul id="friendsList">
</ul>

Node.parentElement is a read only property (ie if you want to inspect the parent node of a given node)
If you want to insert nodes there are different ways:
one of the solution is to use the method appendChild on the parent node.
If you want to avoid a reflow (the browser redraws the frame) one every insertion you can first insert your elements in a document fragment
const fragment = document.createDocumentFragment();
for(let name of names){
const li = document.createElement('li');
li.textContent = name;
fragment.appendChild(li);
}
//now you add all the nodes in once
const container = document.getElementById('friendsList');
container.appendChild(fragment);

Try below example - use appendChild on your UL, which you will get using getElementById():
var names = ["John","Mike","George"]
for (var i = 0; i < names.length; i++) {
var name = names[i];
var li = document.createElement('li');
li.innerHTML = name;
document.getElementById('friendsList').appendChild(li);
}
<ul id="friendsList"></ul>

// using Es6
let names = ['john','jane','smith'];
names.forEach((name)=>{
let li = document.createElement('li');
li.innerText = name;
document.getElementById('friendsList').appendChild(li);
})
<ul id="friendsList"></ul>

var friendsList = document.getElementById('friendsList');
var names = ["John","Mike","George"];
names.forEach(function (name) {
var li = document.createElement('li');
li.innerHTML = name;
friendsList.appendChild(li);
});

Related

check for duplicate before appendChild

const pickNewUl = document.getElementById("ullist1");
var createLi = document.createElement("li");
createLi.id = listItems[i].id;
createLi.classList.add(pickNewUlsl);
createLi.innerHTML = listItems[i].textContent;
createLi.innerHTML += "<a onclick='remove(this)' class='removebtn'>X</a>";
pickNewUl.appendChild(createLi);
What I need to check in above code is: I want to check if there are any same id LI exists or not, if not then only it should append, otherwise it will not append.
pickNewUl is a UL list
You can find for any element inside element with .querySelectorAll as below.
if (pickNewUl.querySelectorAll('#' + listItems[i].id).length === 0) {
// Add element
}
Reference : https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
Your complete code should be like below.
const pickNewUl = document.getElementById("ullist1");
if (pickNewUl.querySelectorAll('#' + listItems[i].id).length === 0) {
var createLi = document.createElement("li");
createLi.id = listItems[i].id;
createLi.classList.add(pickNewUlsl);
createLi.innerHTML = listItems[i].textContent;
createLi.innerHTML += "<a onclick='remove(this)' class='removebtn'>X</a>";
pickNewUl.appendChild(createLi);
}
You can just wrap you code inside an if:
// the same as before but using pickNewUl instead of document
if (!pickNewUl.getElementById(listItems[i].id)) {
const createLi = document.createElement("li");
...
pickNewUl.appendChild(createLi);
}
Btw, I suggest to use a different approach excluding duplicated id:
// The string into querySelector method is a template string.
if (!pickNewUl.querySelector(`[data-item-id="${listItems[i].id}"]`)) {
const createLi = document.createElement("li");
createLi.dataset.itemId=listItems[i].id;
...
pickNewUl.appendChild(createLi);
}

Is there an easy way in Javascript to add parameterised event listeners to dynamically generated HTML elements?

I have an ordered list whose list items are generated using Javascript (as the number of items/their contents is variable), and I would like to add an event listener to each item dependant on which element of the list it is - so I want the 1st item to call foo(1), the 2nd element to call foo(2), the 30th element to call foo(30), etc. However, currently all elements are ending up with a listener identical to that of the last element. Code I'm using is shown below:
document.getElementById("mylist").innerHTML = "";
for (i = 0; i < listitems.length; i++) {
var li = document.createElement("li");
li.setAttribute("id", "listitem" + i);
li.addEventListener("click",function(){foo(i)})
document.getElementById("mylist").appendChild(li);
}
What about if you use let to declare your i variable:
document.getElementById("mylist").innerHTML = "";
for (let i = 0; i < listitems.length; i++) {
var li = document.createElement("li");
li.setAttribute("id", "listitem" + i);
li.addEventListener("click",function(){foo(i)})
document.getElementById("mylist").appendChild(li);
}
Reference: 'let' vs 'var' in javascript for loops, does it mean that all the for loops using the 'var i =0' should actually be 'let i =0' instead?
You have to try as below to capture variable inside for loop to set event listener. Find Creating closures in loops: A common mistake in this document.
Update your event listener assignment as li.addEventListener("click", function(){ var index = i; return foo(index); });.
Complete code is as below.
document.getElementById("mylist").innerHTML = "";
for (i = 0; i < listitems.length; i++) {
var li = document.createElement("li");
li.setAttribute("id", "listitem" + i);
li.addEventListener("click", function(){ var index = i; return foo(index); });
document.getElementById("mylist").appendChild(li);
}

Problem with Looping through over a newly created list element by js

I am building a Todo-List Project and i am stuck at looping through my newly created list items.
This is what i am doing:
Created an array.
Made li items for array's each element through looping so that array appears in a list manner.
And then looping through newly created li section to addEventListener on each of li's ( But this one is not working).
var arrList = ["play","learn","walk"];
var list = document.querySelectorAll("li");
var done = false;
//printing array in list manner
for(let i = 0; i < arrList.length; i++){
let el = document.createElement("li")
el.textContent = arrList[i];
document.querySelector("ul").appendChild(el);
}
//looping through each li's to apply if else statement
for(let i = 0; i < list.length; i++){
list[i].addEventListener("click",function(){
if(!done){
this.style.textDecoration = "line-through";
done = true;
}else{
this.style.textDecoration = "none";
done = false;
}
})
}
You're code is mostly correct, however there are a few issues that need to be addressed. First, consider replacing your for loop with iteration based on forEach() as shown below. Using forEach() in this way allows you to leverage "closure" which in this case will greatly simplify your code. For instance, you can use the closure feature to store the done state of each item in your list, rather than storing that state explicitly in an array.
The other issue I noticed was var list = document.querySelectorAll("li"); queries the document for li elements before any are added to your document - later in your script it seems you're iterating that empty query result and expecting it to contain the added li elements.
Here's a working snippet - hope this helps!
var arrList = ["play", "learn", "walk"];
// Iterate the list via forEach
arrList.forEach(function(arrItem) {
// We're now in a new "closure" for this list item
// so we can define some state like "done" that will
// be used exclusively for this list item
var done = false;
// Create li element for this list item as before
var el = document.createElement("li")
el.textContent = arrItem;
// Configure click event
el.addEventListener("click", function() {
// Notice we're able to use the done variable
// in this closure for this list item? The key
// thing to understand is that each list item
// will have it's own unique "done" variable
if (!done) {
el.style.textDecoration = "line-through";
done = true;
} else {
el.style.textDecoration = "none";
done = false;
}
})
document.querySelector("ul").appendChild(el);
});
<ul></ul>
It seems like you only have one done variable that is shared for every item on the todo list. Therefore if you click one of the items all of the items will be crossed out. You will need a boolean variable for every item in your to do list.
Add this line just above the second for loop and remove from the top.
var list = document.querySelectorAll("li");
You are assigning list the values even before they are created.
from the source code I see that the list li item is initialized before new li item been created,
it will cause the list li item not contains the new one,
due to that addEventListener will not working for the new item.
to fix this, just need move init list li item code after creation part :
var arrList = ["play","learn","walk"];
var done = false;
//printing array in list manner
for(let i = 0; i < arrList.length; i++){
let el = document.createElement("li")
el.textContent = arrList[i];
document.querySelector("ul").appendChild(el);
}
var list = document.querySelectorAll("li");
//looping through each li's to apply if else statement
for(let i = 0; i < list.length; i++){
list[i].addEventListener("click",function(){
if(!done){
this.style.textDecoration = "line-through";
done = true;
}else{
this.style.textDecoration = "none";
done = false;
}
})
}
Please, be simple...
var
arrList = ["play","learn","walk"],
UL_arrList = document.querySelector("ul")
;
arrList.forEach (arrItem => {
let el = document.createElement("li");
el.textContent = arrItem;
UL_arrList.appendChild(el);
el.onclick = function(e){
let deco = this.style.textDecoration || 'none';
this.style.textDecoration = (deco==='none') ? 'line-through': 'none';
}
});
<ul></ul>

creating a new list for each index from the array

My solution:
https://jsfiddle.net/c96hv9tj/1/
function filler(list, arr){
let b = document.createElement("li");
for(let i = 0; i < arr.length; i++){
b.appendChild(document.createTextNode(arr[i]));
}
list.appendChild(b);
}
I'm trying to make it create a new li for each index from the array
help please.
You need to put everything inside the loop like this :
function filler(list, arr) {
for (let i = 0; i < arr.length; i++) {
let b = document.createElement("li");
b.appendChild(document.createTextNode(arr[i]));
list.appendChild(b);
}
}
let ul = document.getElementById("fillthislist");
let entries = ["Shmi", "Anakin", "Luke"];
filler(ul, entries);
<section>
<h1>Fill an empty list with the contents of an array</h1>
<ul id=fillthislist>
</ul>
</section>
For better performance don't appendChild to the document element. Use a Document Fragment instead.
function filler(list, listItems) {
var fragment = document.createDocumentFragment();
listItems.forEach(item => {
let li = document.createElement('li');
li.appendChild(document.createTextNode(item));
fragment.appendChild(li);
});
list.appendChild(fragment);
}
Since the document fragment is in memory and not part of the main DOM
tree, appending children to it does not cause page reflow (computation
of element's position and geometry). Consequently, using document
fragments often results in better performance.
JsFiddle example:
https://jsfiddle.net/c96hv9tj/11/

Want to set li innerHTML of ul

I'm writing a javascript function where I get a ul object from my HTML and want to set the text of one of the li elements in theul`. I'm doing:
list = document.getElementById('list_name');
Then I want to access the ith li element of list using a loop.
I have:
for (i = 0; i < 5; i++) {
list[i].innerHTML = "<a>text</a>";
}
but this is not working. What is the proper way to do it?
You need to access the child li elements of the ul. JavaScript and the DOM API can't automagically do that for you.
var list = document.getElementById('list_name'),
items = list.childNodes;
for (var i = 0, length = childNodes.length; i < length; i++)
{
if (items[i].nodeType != 1) {
continue;
}
items[i].innerHTML = "<a>text</a>";
}
You could also use getElementsByTagName('li') but it will get all descendent li elements, and it seems you want only the direct descendants.
You could also avoid innerHTML if you want.
var a = document.createElement('a'),
text = document.createTextNode('text');
a.appendChild(text);
items[i].appendChild(a);
innerHTML can cause issues, such as lost event handlers and the performance issue of serialising and re-parsing the HTML structure. This should be negligible in your example, however.
jQuery Sample code, although the others work:
$("#list_name li").text("<a href=''>text</a>");
Its much more succinct with jQuery
You can try the following
var el = document.createElement("li"),
content = document.createTextNode("My sample text"),
myUl = document.getElementById("ulOne");
el.appendChild(content);
el.id = "bar";
myUl.appendChild(el);
Here's the demo: http://jsfiddle.net/x32j00h5/
I prefer a aproach using getElemenetByTagName, if somehow you get a extra node like a script tag or a span you will have problems. A guess this code will help you:
var list = document.getElementById("mylist");
var items = list.getElementsByTagName("li");
for(var i = 0, size = items.length; i< size; i++){
items[i].innerHTML = "<a href='#'>LINK</a>";
}

Categories

Resources