Rares
Rares

Reputation: 141

JavaScript appendChild replace the old Child

I am trying to make a image grid with download buttons using javascript to put them in html.

I tried insertBefore.

var list = ["https://via.placeholder.com/50", "https://via.placeholder.com/75", "https://via.placeholder.com/100", "https://via.placeholder.com/125"];
var template, item, item1, item2, fin, i, target, ta;
template = document.getElementById("item");
item = template.content.getElementById("grid-itm");
item1 = template.content.getElementById("imgtit");
item2 = template.content.getElementById("linktit");
target = document.getElementById("gc");
for (i = 0; i < list.length; i++) {
  target = document.getElementById("gc");
  ta = list[i];
  item1.src = ta;
  item2.href = ta;
  item.appendChild(item1);
  item.appendChild(item2);
  target.appendChild(item);
}
<template id="item">
  <div class="grid-item" id="grid-itm">
  </div>
  <img src="" id="imgtit">
  <a href="" id="linktit"><p>Download</p></a>
</template>
<div class="grid-container" id="gc"></div>

In .grid-container should be all my pictures, but it's only the last from the list.

Upvotes: 0

Views: 1172

Answers (2)

zer00ne
zer00ne

Reputation: 43940

Problems

  • The content of a <template> must be cloned

    const copy = template.content.cloneNode(true)
    

    The parameter for cloneNode(param) is a Boolean -- true will clone all of targeted tag's descendant tags.

  • ids must be unique, otherwise HTML is invalid. Moreover JavaScript/jQuery that manipulates DOM (such as OP) will break. Assign class to duplicated tags and use .querySelector() to reference them.

    const image = copy.querySelector('.image');
    
  • Clone and reference template content and assign clone properties within the loop

    for (let url of list) {
      const copy = template.content.cloneNode(true);
      const image = copy.querySelector('.image');
      image.src = url;
      document.body.appendChild(copy);
    }
    

    Always modify the DOM as the last step of any process. Although mostly relevant in large scale applications, performance suffers the most when removing, adding, mutating, traversing, etc. anything in the DOM. It costs less in memory and processing time when modifying a tag not attached to DOM (ex. image.src = url; then document.body.appendChild(copy);)

const list = ["https://via.placeholder.com/50", "https://via.placeholder.com/75", "https://via.placeholder.com/100", "https://via.placeholder.com/125"];

function imgGrid(array) {
  const grid = document.querySelector(".grid");
  const template = document.querySelector(".temp");

  for (let url of array) {
    const item = template.content.cloneNode(true);
    item.querySelector('.image').src = url;
    item.querySelector('.link').href = url;
    grid.appendChild(item);
  }
}

imgGrid(list);
.grid {
  display: flex;
  flex-wrap: wrap;
  max-width: 100vw
}

.item {
  text-align: center;
  width: fit-content;
}
<section class="grid"></section>

<template class="temp">
  <figure class="item">
  <img src="" class="image">
  <figcaption>
    <a href="" class="link">Download</a>
  </figcaption>
  </figure>
</template>

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 370889

You only assign to the item variables once, before the loop begins, and when you call appendChild with an element already in the DOM, it will be removed from where it existed previously. Inside the loop, clone the elements instead (and remove their IDs, since duplicate IDs in a single document is invalid HTML):

const list = ["IMG_20190704_133046.jpg", "IMG_201810055.jpg", "DSCN0994.JPG", "IMG_20181104_160735.jpg", "IMG_201810054.jpg", "IMG_20181007_152306.jpg", "IMG_20180721_210459.jpg", "PANO_20180719_202625-01.jpeg", "IMG_20180719_200505.jpg"];
const target = document.getElementById("gc");
const template = document.querySelector('#item');
for (let i = 0; i < list.length; i++) {
  const [div, img, a] = [...template.content.children].map(node => node.cloneNode());
  const src = "imgs/" + list[i];
  img.src = src;
  a.href = src;
  div.appendChild(img);
  div.appendChild(a);
  target.appendChild(div);
}

const list = ["IMG_20190704_133046.jpg", "IMG_201810055.jpg", "DSCN0994.JPG", "IMG_20181104_160735.jpg", "IMG_201810054.jpg", "IMG_20181007_152306.jpg", "IMG_20180721_210459.jpg", "PANO_20180719_202625-01.jpeg", "IMG_20180719_200505.jpg"];
    const target = document.getElementById("gc");
    const template = document.querySelector('#item');
    for (let i = 0; i < list.length; i++) {
      const [div, img, a] = [...template.content.children].map(node => node.cloneNode());
      const src = "imgs/" + list[i];
      img.src = src;
      a.href = src;
      div.appendChild(img);
      div.appendChild(a);
      target.appendChild(div);
    }
<template id="item">
  <div class="grid-item">

  </div>
  <img>
  <a><p>Download</p></a>
</template>

<div id="gc"></div>

Upvotes: 2

Related Questions