Search code examples
vue.jsvuejs2bootstrap-vue

How to handle infinite GET Image requests when dealing with broken image url in Vue 2?


I'm developing a new version of my website in Vue 2 and I have created a component to handle image broken links, swapping the url domain, in order to display images stored in my local host and also those stored in the production server. The problem is that sometimes the image filename in the server is different than what is set on my local host database (because the user changed the image on the production live version), and then I get infinite requests looping in the console since neither image url are valid.

I'm also using Bootstrap-Vue to lazy-load the images.

This is my code:

<template>

  <b-img-lazy :src="'https://example.com/uploads/' + photo" @error.native="replaceSrc" :alt="titulo" :title="title" class="thumb"></b-img-lazy>

</template>
<script>

export default {
    name: "ImgCarousel",
    props: {
        photo: {
            type: String
        },
    title: {
      type: String
    }
    },
    data: function () {
        return {
            index: null
        }
    },
    methods: {
        replaceSrc(e) {
            e.target.src = 'http://localhost:8888/uploads/' + this.photo;
        },
    }
}
</script>

How do I stop the GET requests from entering a infinite loop?


Solution

  • Try to check if image exists:

    new Vue({
      el: '#demo',
      data: function () {
        return {
          startImg: 'https://picsum.photos/150',
          index: null,
          photo: '100',
          title: '',
          titulo: '',
          url: 'https://picsum.photos/'
        }
      },
      methods: {
        replaceSrc(e) {
          this.checkIfImageExists(this.url + this.photo, (exists) => { 
            exists ?
              e.target.src = this.url + this.photo :
              this.titulo = 'no image'
          })
        },
        checkIfImageExists(url, callback) {
          const img = new Image();
          img.src = url;
          if (img.complete) {
            callback(true);
          } else {
            img.onload = () => callback(true)
            img.onerror = () =>  callback(false)
          }
        },
        change() {
          this.startImg = this.startImg ? '' : 'https://picsum.photos/150'
        },
        breakSource() {
          this.startImg = "wrong url"
          this.photo = "wrong url"
        }
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
    <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" />
    <script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
    <script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue-icons.min.js"></script>
    <div id="demo">
      <div>
      <b-img-lazy :src="startImg" @error.native="replaceSrc" :title="title" :alt="titulo" class="thumb"></b-img-lazy>
      </div>
      <button @click="change">Change source</button>
      <button @click="breakSource">Break source</button>
    </div>