Reputation: 243
When I send a request to api and render the result as a list, some images are showing late and text are rendered first. Is there any way to prevent this?
I want to show the list only when images, classes, text are totally finished computing by logic. If they are not ready, I want to still hide them. v-cloak is not working!.
This is the part I'm getting trouble.
You can see, also the entire list is rendered, there are some images left.
Here is my code example.
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<!-- thre may be some more logics -->
<img :src="todo.img" width="100px">
{{todo.name}}
</li>
</ol>
</div>
new Vue({
el: "#app",
data: {
todos: []
},
created: function(){
this.requestApi();
},
methods: {
requestApi(){
this.todos = [
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "AAA" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "BBB" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "CCC" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "DDD" }
];
}
}
})
https://jsfiddle.net/vxy4gnj8/3/
It's not showing clearly my problem in above jsfiddle because it's not sending to a real api and rendered too fast.
Upvotes: 0
Views: 979
Reputation: 127
requestApi(){
const vm = this;
const list = [
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "AAA" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "BBB" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "CCC" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "DDD" }
];
Promise.all(
list.map(item=>new Promise((resolve,reject)=>{
const img = new Image();
img.addEventListener("load",function(){
// here this means the img element
this.__isOK__ = true;
resolve(this);
},{once:true})
img.addEventListener("error",function(){
this.__isOK__ = false;
resolve(this);
},{once:true});
img.src = item.img;
}))
).then(arr=>{
const success = arr.filter(img=>img.__isOK__);
console.log(`Finish. We had loaded ${arr.length} pictures. ${success.length} of them was successed`);
vm.todos = list;
})
}
Upvotes: 1
Reputation: 22393
You can use v-if
to only show component when requestApi
finished:
<div id="app">
<div v-if="!isLoading">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<!-- thre may be some more logics -->
<img :src="todo.img" width="100px">
{{todo.name}}
</li>
</ol>
</div>
</div>
new Vue({
el: "#app",
data: {
todos: [],
isLoading: true
},
created: function(){
this.requestApi();
},
methods: {
requestApi(){
this.todos = [
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "AAA" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "BBB" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "CCC" },
{ img: "https://steamcdn-a.akamaihd.net/apps/dota2/images/mars/hero_mars93fd33s5.jpg", name: "DDD" }
];
this.isLoading = false
}
}
})
Note that isLoading
is used as a flag to check if request finishes or not.
Upvotes: 1