1

I am trying to dynamically add elements created in JS to HTML, but would like to know the most efficient way of doing this. For example adding users to a list, the result would be:

<div id="user-list" style="display:flex; flex-direction:column">

 <div id="user-1">
  <span class="photo" style="width:25%">PHOTO</span>
  <span class="name" style="width:25%">name</span>
  <span class="surname" style="width:25%">surname</span>
  <span class="age" style="width:25%">age</span>
 </div>

 <div id="user-2">
  <span class="photo" style="width:25%">PHOTO</span>
  <span class="name" style="width:25%">name</span>
  <span class="surname" style="width:25%">surname</span>
  <span class="age" style="width:25%">age</span>
 </div>

</div>

I tried these 2 ways:

document.getElementById("user-list").innerHtml +=  
       `<div id="user-${userId}">
         <span class="photo" style="width:25%">${userPhoto}</span>
         <span class="name" style="width:25%">${userName}</span>
         <span class="surname" style="width:25%">${userSurname}</span>
         <span class="age" style="width:25%">${userAge}</span>
        </div>`

and

var user = document.createElement("div");
user.id = `user-${userId}`

var photo = document.createElement("span");
photo.setAttribute('style','width:25%')
photo.innerHTML = userPhoto;

var name = document.createElement("span");
name.setAttribute('style','width:25%')
name.innerHTML = userName;

var surname = document.createElement("span");
surname.setAttribute('style','width:25%')
surname.innerHTML = userName;

var age = document.createElement("span");
age.setAttribute('style','width:25%')
age.innerHTML = userAge;

user.appendChild(photo);
user.appendChild(name);
user.appendChild(surname);
user.appendChild(age);

document.getElementById("user-list").appendChild(user);

And it would loop creating and adding all the users (for example 20 users).

Which would be more efficient?

  • The first method is much simpler imo. – Pranev Jun 13 '22 at 16:14
  • 2
    [`.innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) is most definitely NOT the most efficient way. In fact, `innerHTML` should be avoided as it has, not only performance issues (the HTML parser must reconstruct the DOM each time it is used), but also can expose your code to injection attacks. `document.createElement()` may be more code, but it will perform better and is more secure. – Scott Marcus Jun 13 '22 at 16:14
  • 1
    Additionally, if you are working with strings that don't contain any HTML, you should definitely be using [`.textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent) instead of `.innerHTML` as `.textContent` doesn't rebuild the DOM (so it performs better). Also, instead of this syntax: `name.setAttribute('style','width:25%')`, you can just access the HTML attribute as JavaScript property, like this: `name.style.width = "25%";` – Scott Marcus Jun 13 '22 at 16:18
  • 3
    @Pranev Simpler is not always better. See my comment above as to why `.innerHTML` should always try to be avoided. – Scott Marcus Jun 13 '22 at 16:19
  • thanks for the suggestions, I am working with a lot more classes, ids and styles, I just tried to make the example simple so the question could be understood easier. So it would be best to use the createElement() function even if an element has 10 other elements created inside of itself? – Kjut Nikolas Jun 13 '22 at 16:22
  • 3
    It would be better than `.innerHTML`, but the answer from @Hewr Chelsea below about using `template` would probably be best for larger "chunks" of markup. – Scott Marcus Jun 13 '22 at 16:24
  • Does this answer your question? [Advantages of createElement over innerHTML?](https://stackoverflow.com/questions/2946656/advantages-of-createelement-over-innerhtml) – James Jun 13 '22 at 16:31
  • Also note, that questions about the "most efficient way" will be always opinion-based and as such out of scope for SO. – tacoshy Jun 13 '22 at 16:55

3 Answers3

2

I would use html <template> tag. You will have the elements and will be able to fill it with the data through the loop. Example:

const template = document.querySelector('template')
const clone = template.content.cloneNode(1).firstElementChild

and you will be able to clone this template inside the loop for each entry, and will be able to select elements from it using:

clone.querySelector('<selector>')

when you have filled the template with data, you can add this clone element to the dom or any element. Like this:

document.appendChild(clone)

for more information check out html template tag with examples

Hef
  • 606
  • 6
  • 16
1

There multiple way you can modify the DOM. With document.createElement, insertAdjacentHTML, insertAdjacentText, insertAdjacentElement, cloneNode or most easiest would be innerHTML.

Adding static element that not going to interact with use any way, insertAdjacentHTML, insertAdjacentText, insertAdjacentElement, innerHTML would do great job for you.


But with document.createElement you get more control over that DOM element. Allows you to add listeners, add and update attributes, and even remove elements from DOM in the easiest way.

Just a quick effort to show you, but definitely, you can use js more efficiently than this to manage elements within the document.

const employees=[{userId:"56146443",age:52,jobTitleName:"Developer",firstName:"Romin",lastName:"Irani",preferredFullName:"Romin Irani",employeeCode:"E1",region:"CA",phoneNumber:"408-1234567",emailAddress:"romin.k.irani@gmail.com"},{userId:"28949847",age:45,jobTitleName:"Developer",firstName:"Neil",lastName:"Irani",preferredFullName:"Neil Irani",employeeCode:"E2",region:"CA",phoneNumber:"408-1111111",emailAddress:"neilrirani@gmail.com"},{userId:"8934656",age:29,jobTitleName:"Program Directory",firstName:"Tom",lastName:"Hanks",preferredFullName:"Tom Hanks",employeeCode:"E3",region:"CA",phoneNumber:"408-2222222",emailAddress:"tomhanks@gmail.com"}];
    const tableHeadings = ['User Id', 'Age', 'Job Title', 'First Name', 'Last Name', 'Preferred Full Name', 'Employee Code', 'Region', 'Phone Number', 'Email Address', 'Change Status', 'Remove'];

    function Cell(data){
      this.render = () => {
        const cell = document.createElement('td');
        cell.append(data);
        return cell;
      }
    }

    function Row(data, deleteRow){
      this.isDisabled = false;
      this.handleDisableAction = () => {
        this.isDisabled = true;
      }
      this.handleDeleteAction = () => {
        deleteRow(data.userId);
      }
      this.render = () => {
        const row = document.createElement('tr');
        row.classList.add(data.age > 50? 'danger': 'normal');
        row.append(...Object.values(data).map(d => {
          const cell = new Cell(d).render();
          cell.innerHTML = d;
          return cell;
        }))

        const buttonDisable = document.createElement('button');
        buttonDisable.textContent = this.isDisabled ? 'Enable' : 'Disable';
        buttonDisable.classList.add(this.isDisabled ? 'disabled': 'enabled');
        buttonDisable.addEventListener('click', this.handleDisableAction.bind(this));
        row.append(new Cell(buttonDisable).render());

        const buttonDelete = document.createElement('button');
        buttonDelete.textContent = 'Delete';
        buttonDelete.addEventListener('click', this.handleDeleteAction.bind(this));
        row.append(new Cell(buttonDelete).render());

        return row;
      }
    }

    function TableHeader(data){
      this.render = () =>{
        const tableHeader = document.createElement('tr');
        tableHeader.append(...data.map(d => new Cell(d).render()));
        return tableHeader;
      }
    }

    function Table(data){
      this.handleDeleteRow = (rowId) => {
        data = data.filter(d => d.userId !== rowId);
        alert(`${rowId} will be deleted soon`);
      }
      this.render = () =>{
        const table = document.createElement('table');
        table.setAttribute('border', 1);
        table.append(new TableHeader(tableHeadings).render())
        table.append(...data.map(d => {
          const row = new Row(d, this.handleDeleteRow).render();
          return row;
        }))
        return table;
      }
    }

    document.body.append(new Table(employees).render());
table{ width: 100%; }
tr.danger{ background-color: orange; }
td{ padding: 5px; }

Suggestions are welcome.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
MORÈ
  • 2,480
  • 3
  • 16
  • 23
0

to create and append HTML elements dynamically use this code snippet.

    <script>

    'use strict';


    const createDynamicElements = (elType,elId,elClass,elInnerHtml) => {

        const el = document.createElement(elType);
        el.setAttribute('id',elId);
        el.setAttribute('class',elClass);
        el.innerHTML = elInnerHtml
        document.body.appendChild(el);

    }


    let elType      = 'div';
    let elId        = 'div-id';
    let elClass     = 'div-class';
    let elInnerHtml = `<p>Hai this is para</p>`;

   createDynamicElements(elType,elId,elClass,elInnerHtml); 

   </script>