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" ></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?
CodePudding user response:
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" ></b-img-lazy>
</div>
<button @click="change">Change source</button>
<button @click="breakSource">Break source</button>
</div>
CodePudding user response:
I also reached the solution below. Probably not elegant as Nikola's answer, although it needs less coding. Basically it adds a counter on each call for "replaceSrc" to prevent looping on the broken links:
<template>
<b-img-lazy :src="'https://example.com/uploads/' photo" @error.native="replaceSrc" :alt="title" :title="title" ></b-img-lazy>
</template>
<script>
export default {
name: "ImgCarousel",
props: {
photo: {
type: String
},
title: {
type: String
}
},
data: function () {
return {
counter: 0
}
},
methods: {
replaceSrc(e) {
if (this.counter == 0) {
e.target.src = 'http://localhost:8888/uploads/' this.photo;
this.counter ;
} else if (this.counter == 1) {
e.target.src = 'https://via.placeholder.com/300x190';
this.counter ;
}
},
}
}
</script>
BTW the "index: null" data on my question was a wrong code I forgot to remove.