1

How do I check if an image is available and render it if so?

So far I have tried something like this, but does not give a true condition.

<div v-for="owner in organisation.owners"
    <div v-if="`https://intranet.com/Lists/CustomPortraits/${owner.employeeId}.jpg`" :style="`background-image:url(https://intranet.com/Lists/CustomPortraits/${owner.employeeId}.jpg)`" class="user-profile-image"/>
    <div v-else class="user-avatar"> <span/>{{ owner.name | nameInitials }} </div>
m_schou
  • 113
  • 1
  • 16
  • 1
    Does this answer your question? [Check if image exists on server using JavaScript?](https://stackoverflow.com/questions/18837735/check-if-image-exists-on-server-using-javascript) – Michal Levý Jun 22 '21 at 13:59
  • An how to do this the best way in vue.js? – m_schou Jun 22 '21 at 14:04

1 Answers1

2

Checking image exists on the server in JS is well described in another SO question - Check if image exists on server using JavaScript?

So it is easy just to choose one of the solutions and integrate it into Vue. Since you want to use it in the v-for loop, plain function is a bad solution. Better will be to introduce computed property and extend existing object with some new properties:

Update

Deleted my previous code - computed is a bad choice either in this case because array/objects returned from computed prop is not reactive data (changing the content of object returned by computed will NOT trigger Vue re-render)

New example below shows solution combining deep watching input data (organisation) + maintaining extended data in the data part of the component...

const vm = new Vue({
  el: '#app',
  data() {
    return {
      // this if external input in question (prop maybe)
      organisation: {
        owners: [{
            employeeId: 100,
            name: "Bill",
          },
          {
            employeeId: 200,
            name: "Murray",
            fail: true // just for demo purposes
          },
          {
            employeeId: 300,
            name: "Billy",
          },
        ]
      },
      ownersWithImage: [],
    }
  },
  methods: {
    checkImageExists(owner) {
      const img = new Image()
      img.onload = () => {
        owner.doesImageExist = true
      }
      img.onerror = () => {
        owner.doesImageExist = false
      }
      img.src = owner.imageUrl
    },
    extendOwnerWithImage(owner) {
      const extendedOwner = {
        ...owner,
        imageUrl: 'https://www.fillmurray.com/250/' + owner.employeeId,
        doesImageExist: false // default
      }
      if (!owner.fail) // just for demo purposes
        this.checkImageExists(extendedOwner)

      return extendedOwner
    }
  },
  watch: {
    'organisation.owners': {
      handler: function() {
        this.ownersWithImage = this.organisation.owners.map(this.extendOwnerWithImage)
      },
      immediate: true,
      deep: true
    }
  },
})
.user-profile-image {
  width: 150px;
  height: 150px;
  background-size: cover;
  background-position: top center;
  border-radius: 50%;
  background-color: grey;
  text-align: center;
  vertical-align: middle;
  line-height: 150px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div v-for="owner in ownersWithImage" :key="owner.employeeId">
    <div v-if="owner.doesImageExist" :style="`background-image:url(${owner.imageUrl})`" class="user-profile-image">
      <span>{{ owner.name }}</span>
    </div>
    <div v-else class="user-profile-image"><span>{{ owner.name }}</span></div>
  </div>
</div>
Michal Levý
  • 33,064
  • 4
  • 68
  • 86