Home > Enterprise >  How to check if image loads and set it as background-image of a cloned template
How to check if image loads and set it as background-image of a cloned template

Time:12-27

I have an HTML template I'm calling for some API and receive a list of objects

I run in loop on all objects and for each create a clone of the template:

const data = [{
  id: 'someid',
  poster: 'some_image_url',
  url: 'some_link_url',
  title: 'Title',
  description: 'description'
}]
const construct = data => {
  const template = document.querySelector('#type1')
  const clone = template.content.cloneNode(true)
  clone.querySelector('a').setAttribute('href', data.url)
  clone.querySelector('.poster').setAttribute('style', `background-image: url("${data.poster}")`)
  clone.querySelector('.title').textContent = data.title
  clone.querySelector('.description').textContent = data.description
  return clone
}
data.forEach(data => document.body.appendChild(construct(data)))
<template id="type1">
  <div class='type1'>
    <a>
      <div class='poster'></div>
      <div class='content'>
        <div class='title'></div>
        <div class='description'></div>
      </div>
    </a>
  </div>
</template>

So far everything works just fine. The problem begins when I decide to check if the image in the poster link is loaded, and if not - set some default image. First I tried to do the following (instead of clone.querySelector('.poster')):

const img = new Image
img.onload = function() {
  clone.querySelector('.poster').setAttribute('style', `background-image: url("${data.poster}")`)
}
img.onerror = function() {
  clone.querySelector('.poster').setAttribute('style', 'background-image: url("./assets/default.png")')
}
img.src = data.poster

And I received the following error: clone.querySelector(...) is null

I tried to use closures:

img.onload = (function (clone) {
  return function () {
    clone.querySelector('.poster').setAttribute('style', `background-image: url("${data.poster}")`)
  }
})(clone)
img.onerror = (function (clone) {
  return function () {
    clone.querySelector('.poster').setAttribute('style', 'background-image: url("./assets/default.png")')
  }
})(clone)

Alas, same result, same error.

I also tried to use .apply(clone) on the methods above, however in that case all the images were set to default image in the onerror method, even though the URL in data.poster did return an image.

Why is this happening and how to make it work?

CodePudding user response:

Save the poster element before the async load event handlers. It seems the clone element is out of scope at the time of the onl oad of the image

const data = [{
  id: 'someid',
  poster: 'https://www.freecodecamp.org/news/content/images/2021/06/w-qjCHPZbeXCQ-unsplash.jpg',
  url: 'some_link_url',
  title: 'Title',
  description: 'description'
}]
const construct = data => {
  const template = document.querySelector('#type1')
  const clone = template.content.cloneNode(true)
  const poster = clone.querySelector('.poster')
  const img = new Image()
  
  img.onload = function() { 
    poster.setAttribute('style', `background-image: url("${data.poster}")`)
    console.log(poster.style.backgroundImage)
  }
  img.onerror = function() {
    poster.setAttribute('style', 'background-image: url("./assets/default.png")')
  }
  img.src = data.poster

  clone.querySelector('a').setAttribute('href', data.url)
  clone.querySelector('.title').textContent = data.title
  clone.querySelector('.description').textContent = data.description
  return clone
}
data.forEach(data => document.body.appendChild(construct(data)))
.poster { height: 100px; width: 100px ; }
<template id="type1">
  <div class='type1'>
    <a>
      <div class='poster'></div>
      <div class='content'>
        <div class='title'></div>
        <div class='description'></div>
      </div>
    </a>
  </div>
</template>

  • Related