0

So I'm creating a note taking app that persists the notes to local storage. When reloading the page, it is supposed to load those notes and create a list element with each one. Problem is that it only creates the last item. I know the strings are getting pushed to local storage and I know the forEach is cycling through them as expected, so the problem must be in how the DOM is manipulated. Here's the code.

For Each:

notes.forEach(function(index){
        listText.innerHTML = index;
        listDiv.appendChild(listText);
        li.appendChild(listDiv);
        li.appendChild(delButton);
        document.querySelector("ul").appendChild(li);
    });

DOM Variables:

// UI VARIABLES
    const li = document.createElement("li");
    const listDiv = document.createElement("div");
    const listText = document.createElement("div");
    listDiv.className = "listDiv";
    listText.className = "listText";
// DELETE BUTTON
    const delButton = document.createElement("button");
    delButton.innerHTML = "X";
    delButton.className = "delButton";
  • 1
    There's only a single element which the loop appends to the list sequentially. – Teemu Dec 10 '20 at 19:12
  • There's a good description of the behavior of `appendChild` in [the documentation](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild) too. – Teemu Dec 10 '20 at 19:17

2 Answers2

1

What you have here is:

let notes = ['a','b','c','d'];

// UI VARIABLES
    const li = document.createElement("li");
    const listDiv = document.createElement("div");
    const listText = document.createElement("div");
    listDiv.className = "listDiv";
    listText.className = "listText";
// DELETE BUTTON
    const delButton = document.createElement("button");
    delButton.innerHTML = "X";
    delButton.className = "delButton";
    
    notes.forEach(function(index){
        listText.innerHTML = index;
        listDiv.appendChild(listText);
        li.appendChild(listDiv);
        li.appendChild(delButton);
        document.querySelector("ul").appendChild(li);
    });
<ul>

</ul>

The reason it only shows you the last element is that you created the parent div only once, and you keep filling it with new data every time that forEach callback function gets triggerred.

What you have to do instead is to create those elements inside the forEach calback function:

let notes = ['a','b','c','d'];

notes.forEach(function(index){
// UI VARIABLES
    const li = document.createElement("li");
    const listDiv = document.createElement("div");
    const listText = document.createElement("div");
    listDiv.className = "listDiv";
    listText.className = "listText";
// DELETE BUTTON
    const delButton = document.createElement("button");
    delButton.innerHTML = "X";
    delButton.className = "delButton";
    
    
        listText.innerHTML = index;
        listDiv.appendChild(listText);
        li.appendChild(listDiv);
        li.appendChild(delButton);
        document.querySelector("ul").appendChild(li);
    });
<ul>

</ul>
BeHFaR
  • 130
  • 4
  • 12
-4

Without currently having time to read into this one properly, I'm guessing it relates to a 'closure bug / deferred resolution':

E.g. When you use a variable that is declared outside the scope the variable is going to be used in, it will use the value that variable has at the time it runs. It doesn't get a copy of the value at the time the closure is setup.

  • One solution for a regular JScript 'for'-loop at least - use/wrap it in an IIFE instead; e.g.
    //  This will be referenced in another (/following) scope
    var dataValsArray = [
        '...',
        '...',
        '...'
    ];


    for (var idx = 0; idx < dataValsArray.length; idx ++) {
        // IIFE
        (function() {
            var currEle = dataValsArray[idx];

            ...  // CODE HERE
        })();
    }
DennisVM-D2i
  • 416
  • 3
  • 8
  • 2
    Unfortunately, this is not the issue at hand. Please consider waiting to fully read the question before attempting to answer. Thanks though! – Isaac Corbrey Dec 10 '20 at 19:31