Dynamically generating lists without document.write? - javascript

I'm using JavaScript to create a list of links from a text source. Using document.write(), resets/creates a new page which is not desirable. I do not know the amount of items in the list, so precomposing a list and using innerHTML to set values doesn't seem 'do-able' ? How would one go about generating dynamic lists in JS?

You can create elements dynamically by using document.createElement. It could work for example like this:
var container = document.getElementById('my-list'),
items = [],
addItem;
addItem = function (text) {
var elm = document.createElement('li');
elm.innerHTML = text;
container.appendChild(elm);
items.push(elm);
};
// generating random list
var i = 0,
j = Math.floor(Math.random() * 50);
for (i; i < j; i++) {
addItem('list item ' + i);
}

As Matti Mehtonen stated you can use document.createElement(), in order to create dynamically elements. One note on this is that instead of appending the newly created elements directly into a DOMnode, you should instead create a document fragment and append the elements to it, afterwards you append the fragment to the DOMnode. This way the process will be faster.
var items = ['cars', 'toys', 'food', 'apparel'];
function render(elementId, list) {
//getting the list holder by id
var el = document.getElementById(elementId);
//creating a new document fragment
var frag = new DocumentFragment();
//iterate over the list and create a new node for
//each list item and append it to the fragment
for (var i = 0, l = list.lenght; i < l; i++) {
var item = document.createElement('span');
frag.appendChild(item.innerHTML = list[i]);
}
//finally append the fragment to the list holder
el.appendChild(frag);
}
//rendering
render("my-list-holder", list);

Related

what happens with the variable when appended with apprendChild [duplicate]

Trying to create DOM element "gota" from template. First I create template:
function htmlToElement(html) {
var template = document.createElement('template');
template.innerHTML = html;
return template.content.firstChild;
}
let gota = htmlToElement('<div class="gota"><div class="gota-rastro"><div class="rastro"></div></div><div class="gota-cabeza"></div></div>');
Second, I create collection from CSS class "gotea" and iterate for each element to append template:
function gotear() {
let gotas = document.getElementsByClassName('gotea');
for (let i = 0; i < gotas.length; i++) {
gotas[i].appendChild(gota);
}
}
gotear();
This just add "gota" element to a only one random element of the collection:
How can I add this template to ALL elements in a collection?
You're only creating one element. Then you're using that same element with appendChild multiple times, so you move it from one parent to the next.
You can clone the element with cloneNode(true) and append the clone:
gotas[i].appendChild(gota.cloneNode(true));
Side note: You can use insertAdjacentHTML rather than htmlToElement to insert elements based on that HTML directly:
function gotear() {
let gotas = document.getElementsByClassName('gotea');
for (let i = 0; i < gotas.length; i++) {
gotas[i].insertAdjacentHTML(
"beforeend",
'<div class="gota"><div class="gota-rastro"><div class="rastro"></div></div><div class="gota-cabeza"></div></div>'
);
}
}
gotear();
Granted, that means parsing the HTML repeatedly. But if not useful here, it might be useful elsewhere. (There's also insertAdjacentText.)

Copy innerHTML to clipboard from multiple <li> elements

I'm trying to create a greasemonkey script to copy the innerHTML of some <li> elements, but I'm unable to to so because it is a nodelist.
var list = document.querySelectorAll(".bx li");
GM_setClipboard(list.innerHTML)
Iterate and generate the combined result.
var list = document.querySelectorAll(".bx li");
GM_setClipboard(
// convert nodelist to array
// for older browser use [].slice.call(list)
Array.from(list)
// iterate and get HTML content
.map(function(e) {
return e.innerHTML;
})
// combine the HTML contents
.join('')
)
Alternatively, we can use simply for loop which would be better since we don't need to create an extra array.
var list = document.querySelectorAll(".bx li");
// initialize string variable for HTML
var html = '';
// iterate over the nodelist using for loop
for (var i = 0; i < list.length; i++) {
// append the HTML content to the string variable
html += list[i].innerHTML;
}
GM_setClipboard(html);
You need to walk through the list and compose required HTML string:
var list = document.querySelectorAll(".bx li");
var html = "";
for(var n = 0; n < list.length; ++n)
html += list[n].outerHTML;

Javascript For loop appending child only appends first element, then throws error

I'm looping through a js object with a nested for loop, stated below, it appends the first element correctly, but then throws the following error:
Can't set the property className of an undefined reference or empty reference. (not sure if exact error, translating from Dutch...)
function allVideos() {
var sql = "SELECT videos.VideoName, videos.VideoPath FROM videos";
var resultSet = db.query(sql, {json:true}); //returns: [{"VideoName":"timelapse aethon2","VideoPath":"videos\\Roermond Papier\\160424 Time laps Aethon2.avi"},{"VideoName":"timelapse aethon3","VideoPath":"videos\\Roermond Papier\\160424 Time laps Aethon2.avi"}]
var parsed = JSON.parse(resultSet);
var parsedlength = arrLenght(parsed);
//alert(resultSet);
for(var i = 0; i < parsedlength; i++) {
var obj = parsed[i];
//alert(i);
var videoElement = document.getElementById("allVideos");
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
videoElement.appendChild(document.createElement('div'));
videoElement.children[i].id='allVid' + i;
videoElement.children[i].className='col-md-4 col-xs-12';
//alert(typeof key)
var card = document.getElementById('allVid' + i);
alert(i);
card.appendChild(document.createElement('div'));
card.children[i].className='card card-block';
card.children[i].innerHTML = "<h3 class='card-title'>" + obj['VideoName'] + "</h3><button class='btn btn-primary'>Selecteren</button>"
}
}
}
}
[EDIT] added screenshot of how it looks
Your code has some significant logic issues. You're using nested loops, but appending to an element assuming that the outer loop counter will let you index into that element's children to get the element you just appended. Later, you try to get that same element again using getElementById. Then, you append a new element to your newly-created element, but try to access that new element using children[i] on the one you just created — at that point, the card element will only have a single child, so as of the second outer loop, it will fail.
createElement returns the element to you, so there's no reason at all to try to access it via children[i] (either time) or getElementById.
See comments:
function allVideos() {
var sql = "SELECT videos.VideoName, videos.VideoPath FROM videos";
var resultSet = db.query(sql, {json:true});
var parsed = JSON.parse(resultSet);
var parsedlength = arrLenght(parsed);
for(var i = 0; i < parsedlength; i++) {
var obj = parsed[i];
//alert(i);
var videoElement = document.getElementById("allVideos");
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
// Create the card, give it its id and class
var card = document.createElement('div');
card.id='allVid' + i;
card.className='col-md-4 col-xs-12';
// Create the div to put in the card, give it its class and content
var div = document.createElement('div');
card.appendChild(div);
div.className='card card-block';
div.innerHTML = "<h3 class='card-title'>" + obj['VideoName'] + "</h3><button class='btn btn-primary'>Selecteren</button>"
// Append the card
videoElement.appendChild(card);
}
}
}
}
Side note: arrLenght looks like a typo (it should be th, not ht), but moreover, there's no reason to use a function to get the length of an array; it's available via the array's length property: parsedLength = parsed.length.
Side note 2: You may find these ways of looping through arrays useful.
Your problem is the if within the nested for:
if(obj.hasOwnProperty(key)) { ...
The variable i is increased even if the property is not "owned" (when the if condition returns false), so next time that the condition is true, i is out of bounds.

Dexie.js iterating a dynamic list

I am using dexie.js, which is an indexDB wrapper. Anywhoo, I have an array that is called from the user's local storage, and my function is supposed to iterate through every list item in the DB and show it. However, upon clicking on my Butane it only shows the most recent input of name.
Note: You can see the entire database by adding a few values in and checking your local storage.
My JsFiddle:
https://jsfiddle.net/enzp3zws/1/
my html:
<ul id="mane"></ul>
my js:
var db = new Dexie("TestDatabase");
db.version(1).stores({
friends: '++id, name, age'
});
var collection = db.friends;
var placement = document.getElementById('rainman');
var jacement = document.getElementById('rainboy');
var stacement = document.getElementById('mane');
var listed = document.createElement('li');
function addrain(){
collection.each(function(friend){
var element = [friend.name];
for (var i = 0; i < element.length; i++){
listed.textContent = element[i];
document.getElementById('mane').appendChild(listed);
//alert(element); <-- this call alerts all names in database.
}
});
}
Please excuse the randomness of some of these variable names. I don't know what sleep is anymore.
You need to create a new 'li' element each time:
//Remove var listed = ... line in header, then:
function addrain(){
collection.each(function(friend){
var element = [friend.name];
for (var i = 0; i < element.length; i++){
var listed = document.createElement('li');
listed.textContent = element[i];
document.getElementById('mane').appendChild(listed);
}
//alert(element); <-- this call alerts all names in database.
});
}
The reason your code did not work before is that you only created one li element, and repeatedly changed its text and re-inserted it at different locations.

For loop to Iterate through an array and create divs that are siblings of each other

I am trying to get my game2 element to have two child divs containing the contents of the gameTwo array, but what is happening in this script is that the first time it iterates through the loop, it creates the child div I want, but the second time it creates a child of the child. Can someone advise on how I can edit this so that the divs are both siblings of each other?
var gameTwo = ['Kansas', 'Villanova']
var gameTwoText = '';
for (i = 0; i < gameTwo.length; i++) {
gameTwoText += "<div>" + gameTwo[i];
}
var secondGame = document.getElementById('game2').innerHTML = gameTwoText;
You need a closing tag on each div - try:
gameTwoText += "<div>" + gameTwo[i] + "</div>";
Without the </div>, you never close the first div so each subsequent one is created as a child of the last.
As others have said, make sure you close your DIV tag in the loop, however you can always do this the old fashion way which will build the elements via the DOM:
var secondGame = document.getElementById('game2');
var gameTwo = ['Kansas', 'Villanova'];
var div = null;
for (var i = 0, len = gameTwo.length; i < len; i++) {
div = document.createElement('div');
div.appendChild(document.createTextNode(gameTwo[i]));
secondGame.appendChild(div);
}

Categories

Resources