Dawn17
Dawn17

Reputation: 8297

getElementById in a for-loop only displays the first item

Relevant HTML portion

<nav>
 <div class="create_button">+ Create KPI</div>
 <div id="items"></div>
</nav>

Relevant JS portion

    VSS.getService(VSS.ServiceIds.ExtensionData).then(function(dataService) {
        // Get all document under the collection
        dataService.getDocuments("MyCollection").then(function(docs) {

            items = docs

            for(var i = 0; i < docs.length; i++) {
                console.log('doclen', docs.length)
                console.log(items[i].name)
                document.getElementById("items").innerHTML = "KPI Name : " + items[i].name;
            }
        });
    });

My JS code fetches all data that I have in my VSTS storage. The docs contains an object with all items. It returns correctly and items[i].name contains the correct value that I want to display.

But this one just displays the first item in my <div id="items"> and not the rest.

Is this the right usage?

How can I fix it?

Upvotes: 0

Views: 688

Answers (2)

Geuis
Geuis

Reputation: 42297

Here are 2 versions that show different ways to do this. Pay attention to the changes in the code that use es6 style.

VSS.getService(VSS.ServiceIds.ExtensionData).then((dataService) => {
  dataService.getDocuments('MyCollection').then((docs) => {
    // keep a reference to the element instead of searching for it in each loop.
    const itemsDiv = document.getElementById('items');
    const contents = [];

    for (let i = 0; i < docs.length; i++) {
      // using template strings here to show you another way of working with strings in es6
      contents.push(
        `<div>KPI Name : ${docs[i].name}</div>`
      )
    }

    // finally update the target element one time with your contents. 
    // The new line character isn't required, can just use '', but this might be easier to read for you
    itemsDiv.innerHTML = contents.join('\n');
  });
});

More compact version using the map functional array method. But note that this is actually slightly slower than doing a normal for loop because its executing a function on each iteration.

VSS.getService(VSS.ServiceIds.ExtensionData).then((dataService) => {
  dataService.getDocuments('MyCollection').then((docs) => {
    // much more compact version using map. Note that while this is more compact, 
    // its slower than the for loop we did in the previous example
    document.getElementById('items').innerHTML = docs.map((item) => `<div>KPI Name : ${docs[i].name}</div>`).join('\n');
  });
});

Upvotes: 1

Marcus H&#246;glund
Marcus H&#246;glund

Reputation: 16856

The issues occours because you are setting the innerHTML of the items div on each iteration in the loop; meaning that the values will be overwritten every time and only display the last value being set in the loop.

One easy solution is to append a new element instead when you set the values to the items div

for(var i = 0; i < docs.length; i++) {
    console.log('doclen', docs.length)
    console.log(items[i].name)
    var newElement = document.createElement('div');
    newElement.innerHTML = "KPI Name : " + items[i].name;
    document.getElementById("items").appendChild(newElement);
}

Upvotes: 1

Related Questions