use fetch api to present user cards, innerHTML overwrite cards

Asked

Viewed 164 times

2

In this code I access a fake Rest api, I take the data, step for json, but when it comes to presenting the cards of the users I cannot find a good way to do this, innerHTML erases all the cards and only presents the last one.

please answer in js vanila, but if there is no other way...

and already taking advantage of which safety care I have to take in these cases ?

var button = document.getElementById('load');

button.onclick = async function () {
	/* fake api */
	const url = "https://reqres.in/api/users?page=2";  
  
  const elementsArray = document.querySelectorAll(".card-container");
  const containerEl = document.querySelector(".container");  
  
  await fetch(url)
    .then((resp) => resp.json()
    .then(function(myJson){
			
      const data = myJson.data;      
          
      
      /* para cada item cria um card novo na tela */
      data.forEach((item)=>{      	
        
      	 containerEl.innerHTML = 
           '<div class="card-container">'+
             '<img src="'+item.avatar+'" class="card-img"/>'+
             '<h3 class="card-title">'+
             item.first_name +
             '</h3>'+
             '<p card-text>'+
             item.email+
             '</p>'+
           '</div>';          
        
      }) 
      
    })
    ) 	
  
};
body, html{
  margin: 0;
  padding: 0;
}
.container{
   display: flex;
   flex-direction: column;
   flex: 1;
   align-items: center;
   padding: 10vh 0;
}

.card-container{
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 5vh;
  margin-top: 15px;
  
  padding: 10px;
  background: #eee;
}

.card-container:hover{
  cursor: pointer;
  box-shadow: 0 0 5px #888;
}
<div class="container">
  <!-- BUTTON TO LOAD CONTENT -->
 <button id="load" type="button">Load all contents</button>
 
  <!-- CARD 1  -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div>
  
  <!-- CARD 2 -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div>
  
  <!-- CARD 3 -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div> 
</div>

2 answers

4

Use the method .insertAdjacentHTML() instead of .innerHTML

The first parameter describes the position, use "afterbegin" to position before the first child.

If you want to add "after", use "beforeend" as position option, this will add after the last child.

var button = document.getElementById('load');

button.onclick = async function () {
	/* fake api */
	const url = "https://reqres.in/api/users?page=2";  
  
  const elementsArray = document.querySelectorAll(".card-container");
  const containerEl = document.querySelector(".container");  
  
  await fetch(url)
    .then((resp) => resp.json()
    .then(function(myJson){
			
      const data = myJson.data;      
          
      
      /* para cada item cria um card novo na tela */
      data.forEach((item)=>{      	
        
      	 containerEl.insertAdjacentHTML('afterbegin', '<div class="card-container">'+
             '<img src="'+item.avatar+'" class="card-img"/>'+
             '<h3 class="card-title">'+
             item.first_name +
             '</h3>'+
             '<p card-text>'+
             item.email+
             '</p>'+
           '</div>');          
        
      }) 
      
    })
    ) 	
  
};
body, html{
  margin: 0;
  padding: 0;
}
.container{
   display: flex;
   flex-direction: column;
   flex: 1;
   align-items: center;
   padding: 10vh 0;
}

.card-container{
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 5vh;
  margin-top: 15px;
  
  padding: 10px;
  background: #eee;
}

.card-container:hover{
  cursor: pointer;
  box-shadow: 0 0 5px #888;
}
<div class="container">
  <!-- BUTTON TO LOAD CONTENT -->
 <button id="load" type="button">Load all contents</button>
 
  <!-- CARD 1  -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div>
  
  <!-- CARD 2 -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div>
  
  <!-- CARD 3 -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div> 
</div>


Reference:

https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML

  • great guy, answered my question very quickly and simple :) thank you

1


The .innerHTML replaces all the content of the element with another HTML code. As you are using it within a .forEach, will only remain in the element the last HTML resulting from the last loop of the loop, because those of the previous loops will be replaced.

One solution is for you to declare an empty string variable before the foreach and inside the loop go concatenating the HTML code into that variable and after the foreach is completed use the .innerHTML to replace the div HTML at once.

Also include code within a function when the DOM is loaded to prevent variables from having global scope. I used below the function of the event DOMContentLoaded:

document.addEventListener("DOMContentLoaded", function(){
   var button = document.getElementById('load');
   
   button.onclick = async function () {
      /* fake api */
      const url = "https://reqres.in/api/users?page=2";  
     
     const elementsArray = document.querySelectorAll(".card-container");
     const containerEl = document.querySelector(".container");  
     
     await fetch(url)
       .then((resp) => resp.json()
       .then(function(myJson){
   
       let html = ``; // declara variável vazia
            
         const data = myJson.data;      
         
         /* para cada item cria um card novo na tela */
         data.forEach((item)=>{      	
           
             // vai concatenando o HTML
             html += '<div class="card-container">'+
             '<img src="'+item.avatar+'" class="card-img"/>'+
             '<h3 class="card-title">'+
             item.first_name +
             '</h3>'+
             '<p card-text>'+
             item.email+
             '</p>'+
           '</div>';          
           
         }) 
         
         containerEl.innerHTML = html; // insere o conteúdo na div
         
       })
       ) 	
     
   };
});
body, html{
  margin: 0;
  padding: 0;
}
.container{
   display: flex;
   flex-direction: column;
   flex: 1;
   align-items: center;
   padding: 10vh 0;
}

.card-container{
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 5vh;
  margin-top: 15px;
  
  padding: 10px;
  background: #eee;
}

.card-container:hover{
  cursor: pointer;
  box-shadow: 0 0 5px #888;
}
<div class="container">
  <!-- BUTTON TO LOAD CONTENT -->
 <button id="load" type="button">Load all contents</button>
 
  <!-- CARD 1  -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div>
  
  <!-- CARD 2 -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div>
  
  <!-- CARD 3 -->
  <div class="card-container">
    <img src="https://visualsound.com/wp-content/uploads/2019/05/unavailable-image.jpg" width="200px" class="card-img"/>
    <h3 class="card-title">
       TITULO
    </h3>
    <p card-text>
      alguma informação referente a imagem.
    </p>
  </div> 
</div>

  • 1

    thanks, it seems to me the better answer so far.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.