variable null, even without being called - javascript

I'm attempting to use JavaScript to add rows to a table. I created an anonymous function iterate that iterates id names, and that works fine. The problem is somewhere in my class.
class CreateTable{
constructor(text) {
this.text = text
}
makeTableRow(){
let self = this;
let row = document.createElement('tr');
for (let i = 0; i < 1; i++) {
let el = document.createElement('td');
el.setAttribute('id', iterate(i));
row.appendChild(el);
}
let en = document.getElementById('id1');
console.log(en);
en.innerHTML = self.text;
return row;
}
}
I adapted this class from something that already works, with some tweaks. The en variable is returning a typeError:en is null, and I can't figure it out. What I want to do is create two empty td elements with callable ids, and then add text to the first element immediately. What is the actual problem that is going on here?

The document.getElementById() function returns null if there is no element with the specified ID in the DOM. The elements that you create in the loop have not been added to the DOM, they're appended to a tr that isn't in the DOM either (it's just returned from your function without having been appended to anything).
Just add the required text directly at the time you create the element:
makeTableRow(){
let self = this;
let row = document.createElement('tr');
for (let i = 0; i < 1; i++) {
let el = document.createElement('td');
el.setAttribute('id', iterate(i));
if (i === 0) // for first element
el.innerHTML = self.text; // set the content
row.appendChild(el);
}
return row;
}
Incidentally, you say you want to create two td elements, but your loop only runs for one iteration. The for condition should be i < 2 if you want it to run twice.

Is null because doesn't is identifying the "id", that meaning that you are writing your script before the id="id1".
You need to write your script at the end, just before of "body"
.......
<div id="id1">
</div>
.....
<script>
....
</script>
</body>

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.)

Is there any way to cyclically update only a <div> content in pure Javascript?

I'm using a div with a <li> element inside where I add some dynamically created elements (localStorage keys to be more specific). I want to update the div every "x" seconds but only the <div>, not the whole page. I know that it can be done with Ajax and JQuery ($( "#here" ).load(window.location.href + " #here" );).
But is there any way to do this whit pure js?
UPDATE
The specific case is that im picking all the localstorage keys and appending them to a list inside a div. When i use like this (window.onload) it works fine. But I want to update it cyclically. If i use a "setinterval" or a button to call the function the previous keys appends repeatedly. (like: file 1.... then: file 1, file 1 file 2 ... then: file 1 file 1 file 2 file 1 file 1 file 1 file 2 file 3)
window.onload = function cargararchivos() {
localstorage = []
var keys = Object.keys(localStorage);
for (let i = 0; i < keys.length; i++) {
var elemento_lista = document.createElement('li')
elemento_lista.innerHTML = keys[i]
var lista = document.getElementById('lista_archivos')
lista.appendChild(elemento_lista)
localstorage[ keys[i] ] = localStorage.getItem( keys[i] )
elemento_lista.onclick = function()
{alert(JSON.parse(localStorage[keys[i]]))}}
};
This can be done using the setInterval function. It executes a function of your choice after a pre-determined amount of time.
To do this your DIV must have an unique ID, so we can access it using Javascript's getElementById() method.
Here's a simple example, which updates a div with the current time every 1000 milliseconds:
function update() {
document.getElementById("myDiv").innerHTML = new Date();
}
var interval = setInterval(update, 1000);
<div id="myDiv">
</div>
The reason your method works the first time, but doesn't work after that is because the method adds DOM nodes. After the second call, you're seeing DOM nodes from both the first call and second call. After the third call, you'd see nodes from the first, second, and third calls... and so on.
If you want to repeatedly call a method like cargararchivos() that adds DOM nodes, you must first remove any DOM elements that have been previously added. I've updated your code, assuming lista_archivos starts empty (no child elements):
function cargararchivos() {
localstorage = []
var keys = Object.keys(localStorage);
var lista = document.getElementById('lista_archivos')
// Ensure any previously added DOM nodes are removed.
while (lista.firstChild) {
lista.removeChild(lista.firstChild);
}
for (let i = 0; i < keys.length; i++) {
var elemento_lista = document.createElement('li')
elemento_lista.innerHTML = keys[i]
lista.appendChild(elemento_lista)
localstorage[ keys[i] ] = localStorage.getItem( keys[i] )
elemento_lista.onclick = function()
{alert(JSON.parse(localStorage[keys[i]]))}
}
};

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.

JavaScript use for loop to create p tag with innerHTML content filled in

i am using a for loop to generate paragraph tags based on the length of my array. I want each of these p tags generated to have the same innerHTML. I can get the tags to generate with the class name but the innerHTML remains blank.
I have tried the following to no avail, not sure what I am doing wrong.
for (i = 0; i < numArray.length; i++) {
var line = document.createElement("p");
line.className = "line";
document.body.appendChild(line);
var b = document.getElementsByClassName("line");
b.innerHTML = "|";
}
You don't need to call getElementsByClassName you can change the innerHTML of line since you already have the reference to the DOM element.
for (i = 0; i < numArray.length; i++) {
var line = document.createElement("p");
line.className = "line";
line.innerHTML = "|";
document.body.appendChild(line);
}
And explaining why it didn't work, it's because getElementsByClassName returns a collecion of elements, you need to loop through them.
getElementsByClassName should return an array of elements, not a single element. You could try: getElementsByClassName('line')[i], if there is some reason you are doing that specifically.
Note: getElementsByClassName('line')[i] may not refer to the object you just created, unless there are no other "line"s on the page. It scans the document for all elements that have a class called line, which could be paragraphs or other element types.
For a better alternative, please refer to changes made below. This:
caches the numArray length into a variable, so you are not performing that operation at each loop iteration
sets the HTML and ClassName of the element you created before attaching it to the document; which has a number of performance benefits
does not unnecessarily do a DOM lookup for elements, which is expensive
uses the var keyword to avoid scoping conflicts for loop variables
JS Fiddle:
for ( var i=0, n=numArray.length; i < n; i++) {
var line = document.createElement("p");
line.className = "line";
line.innerHTML = '|';
document.body.appendChild(line);
}

Javascript table creation

Trying to create a table using the following code but not working. Please point out where I'm going wrong.
var i,j;
function cell(ih){
var tcell =document.createElement('td');
tcell.innerHTML=ih;
return tcell;
}
mutable=document.createElement('table');
for (i=0;i<10;i++){
row1=document.createElement('tr');
for(j=0;j<10;j++){
row1.appendChild(cell(j));
}
mutable.appendChild(row1);
document.write(mutable);
}
You have several problems, the first two are the big ones, the second two are a matter of style and risk of clashes with other code:
You are trying to document.write HTMLElementNodes. document.write only deals with strings. Grab a container element (e.g. with document.getElementById) and append to it
You are trying to document.write the entire table every time you add a row to it. Append the table once the table is complete, not every time you go through the loop.
You are using globals all over the place, learn to love the var keyword
row1 is a poor variable name for the row you are operating on which usually isn't the first
Use document.body.appendChild(...) instead of document.write(...).
You can do it by changing your script to use document.body.appendChild(mutable) after your nested for loop:
var i,j;
function cell(ih){
var tcell =document.createElement('td');
tcell.innerHTML=ih;
return tcell;
}
mutable=document.createElement('table');
for (i=0;i<10;i++){
row1=document.createElement('tr');
for(j=0;j<10;j++){
row1.appendChild(cell(j));
}
mutable.appendChild(row1);
}
document.body.appendChild(mutable);
This appends the entire mutable table object you've created to the <body> element of your page. You can see it working here.
Also note that most times in markup, you don't see the <tbody> element, but it is good practice to append this as a child element of the <table> and as a parent element for all of your rows. So, your script should look more like this:
function cell(ih){
var tcell = document.createElement('td');
tcell.innerHTML = ih; // I would suggest you use document.createTextNode(ih) instead
return tcell;
}
function appendTable() { // you now have to call this function some time
mutable = document.createElement("table");
var tBody = mutable.appendChild( document.createElement("tbody") ); // technique using "fluid interfaces"
for (var i = 0; i < 10; i++) {
var row1 = tBody.appendChild( document.createElement('tr') ); // fluid interface call again
for(var j = 0; j < 10; j++) {
row1.appendChild(cell(j));
}
}
document.body.appendChild(mutable);
}
I made some style changes to your script, and I would suggest making even more, but as far as correctness, it should work.

Categories

Resources