How to make a callback only when the images from the get request are loaded

I make a request to the address return which returns the generated html.
the request code looks like this:

document.addEventListener("DOMContentLoaded", function() {
    axios.get("/get-cards")
        .then(response => {
            document.getElementById("load").remove();
            $("#content").html(response.data);
        })
        .catch(error => {
            console.log(`ERROR: ${error}`);
        });
});

The page that generates html (at /get-cards) looks like this:

@foreach($technics as $technic)
    <div class="technic-card">
        <div class="card-img">
            <div style="background-image: url('{{ $technic->img_1 }}'" alt="{{ $technic->name }}">
            <div style="background-image: url('{{ $technic->img_2 }}'" alt="{{ $technic->name }}">
            <div style="background-image: url('{{ $technic->img_3 }}'" alt="{{ $technic->name }}">
        </div>
        <div class="card-name">{{ $technic->name }}</div>
        <div class="card-type">{{ $technic->type }}</div>
        <div class="card-footer">
            <div class="card-price">{{ $technic->price }}/час</div>
            <div class="card-buy-btn">арендовать</div>
        </div>
    </div>
@endforeach

I need to add ready-made html with uploaded images to the page, but the following scenario occurs.

  1. loads the page from which the request is sent and then the response (html markup) and added
  2. the loading indicator turns on
  3. the request returns the response
  4. the loading indicator is removed
  5. html code is added to the page
  6. and the images start loading it looks like this

How do I make sure that the loading indicator does not disappear until the images are loaded too?

Author: midnightelf18, 2020-10-09

1 answers

You need to find all the images and wait for them to load

In the example, I put the url of the images in a separate attribute for convenience, but it is quite possible to get element.style from

// вместо getCards будет запрос через axios
getCards()

// когда ответ пришёл
.then(html => {
  
  $('#content').html(html);
  
  let loading = [];
  
  // ищем картинки для прогрузки
  $('#content [data-bg]').each(function(){
    loading.push(new Promise(resolve => {
      // Собираем url которые придётся грузить
      let url = $(this).data('bg');
      // создаём в памяти картинку
      let img = new Image();
      // и грузим её
      img.src = url;
      
      // когда загрузится, ставим её в background-image
      // и отчитываемся о завершении
      img.onload = () => {
        $(this).css('background-image', `url(${url})`);
        resolve();
      }
    }));
  });
  
  // когда всё загрузится
  Promise.all(loading).then(()=>{
    // убираем заглушку
    // и показываем контент
    $('#load').remove();
    $('#content').removeClass('loading');
  })
  
});




function getCards(){
  
  return new Promise(resolve => {
    
    setTimeout(()=>{
      resolve(
      
        `<div class="card">
          <div data-bg="https://via.placeholder.com/350x150?r=${Math.random()}"></div>
          <div data-bg="https://via.placeholder.com/350x150?r=${Math.random()}"></div>
          <div data-bg="https://via.placeholder.com/350x150?r=${Math.random()}"></div>
        </div>

        <div class="card">
          <div data-bg="https://via.placeholder.com/350x150?r=${Math.random()}"></div>
          <div data-bg="https://via.placeholder.com/350x150?r=${Math.random()}"></div>
          <div data-bg="https://via.placeholder.com/350x150?r=${Math.random()}"></div>
        </div>
        `
      
      );
      
    },1000);
    
  })
  
}
.loading{
  display:none;

}

[data-bg]{
  display: inline-block;
  width:70px;
  height:70px;
  background-position: center;
  background-size:cover;
  border: 1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="load">Loading...</div>

<div id="content" class="loading"></div>

You can also use the waitForImages{[5] plugin]}

 1
Author: Ein, 2020-10-09 20:56:04