Search code examples
javascriptajaxcreateelement

Creating multiple elements with javascript


I have an html element tree sample(below) that I want to return with relevant data for every match I got in database.Lets say there are 5 matches. Do I need to create 5 given elements and populate them with javascript data?

I'm gonna run a loop, but this looks like it will be performance costly(creating all element tree for every match). Instead, can i use the given element(pic) populate it with javascript and drop it onto dom instead (x times)? If possible how ?

<!-- sample elem -->
<div class="col-12 col-md-4" style="display: none">
    <div class="card my-3 mx-1">
        <a href="#"><img src="" alt="img"></a>
        <div class="card-body">
            <div class="row">
                <div class="col-12 p-1">Country</div>
                <div class="col-3 p-1">State</div>
                <div class="col-4 p-1">City</div>
            </div>
        </div>
    </div>
</div>

Solution

  • To further elabourate on my comment: it is often the repeated insertion of elements into the DOM tree that causes performance issue, because the document needs to reflow every time a new node is inserted. You should not be worried about calling/invoking document.createElement() too many times: that is the least of your concern.

    Therefore, I would suggest that you use a function to create your entire sample element. You can then invoke this function to create the entire card element as you please in each iteration of the loop, and then append it to the document fragment.

    Pseudo code:

    function createCard() {
      // Create the entire `sample element` as you would call it
      const el = <something>;
      return el;
    }
    
    // Create new document fragment to hold all the nodes
    // At this point, we are NOT injecting them into the DOM yet
    const fragment = new DocumentFragment();
    
    // Go through your data and create new card for each data point
    for (let i = 0; i < 5; i++) {
        fragment.appendChild(createCard());
    }
    
    // Now this is when you insert the entire bulk of the content into the DOM
    document.querySelector('#myInsertionTarget').appendChild(fragment);
    

    A proof-of-concept code is as follow:

    // Since we are creating so many `<div>` elements
    // It helps to further abstract its logic into another function
    function createDivElement(classes, text) {
      const div = document.createElement('div');
      
      if (classes.length)
        div.classList.add(...classes);
      
      if (text)
        div.innerText = text;
      
      return div;
    }
    
    // Call this whenever you want to create a new card
    function createCard(i) {
      const colCountry = createDivElement(['col-12', 'p-1'], 'Country');
      const colState = createDivElement(['col-3', 'p-1'], 'State');
      const colCity = createDivElement(['col-4', 'p-1'], 'City');
      
      const row = createDivElement(['row']);
      row.appendChild(colCountry);
      row.appendChild(colState);
      row.appendChild(colCity);
      
      const cardBody = createDivElement(['card-body']);
      cardBody.appendChild(row);
      
      const image = document.createElement('img');
      image.alt = 'img';
      // Proof-of-concept image source, you can ignore this!
      image.src = `https://placehold.it/100x50?text=Image%20${i+1}`;
      
      const imageLink = document.createElement('a');
      imageLink.href = '#';
      imageLink.appendChild(image);
      
      const card = createDivElement(['card', 'my-3', 'mx-1']);
      card.appendChild(imageLink);
      card.appendChild(cardBody);
      
      const outer = createDivElement(['col-12', 'col-md-4']);
      // outer.style.display = 'none';
      outer.appendChild(card);
      
      return outer;
    }
    
    // Create new document fragment
    const fragment = new DocumentFragment();
    
    // In each iteration of the loop, insert the new card element into fragment
    for (let i = 0; i < 5; i++) {
      const el = createCard(i);
      fragment.appendChild(el);
    }
    
    // When you're done generating the entire set of elements
    // You can then insert the fragment into your DOM (finally!)
    document.querySelector('#app').appendChild(fragment);
    <div id="app"></div>