I am storing relative paths to images in my firebase database for each item I wish to display. I am having trouble getting the images to appear on the screen, as I need to get the images asynchronously. The firebase schema is currently as follows:
{
items: {
<id#1>: {
image_loc: ...,
},
<id#2>: {
image_loc: ...,
},
}
}
I would like to display each of these images on my page with code such as:
<div v-for="item in items">
<img v-bind:src="item.image_loc">
</div>
This does not work, as my relative location points to a place in firebase storage. The relavent code to get the true url from this relative url is:
firebase.storage().ref('items').child(<the_image_loc>).getDownloadURL()
which returns a promise with the true url. Here is my current vue.js code:
var vue = new Vue({
el: '.barba-container',
data: {
items: []
},
firebase: function() {
return {
items: firebase.database().ref().child('items'),
};
}
});
I have tried using computed properties, including the use of vue-async-computed, but these solutions do not seem to work as I cannot pass in parameters.
Basically, how do I display a list of elements where each element needs the result of a promise?
I was able to solve this by using the asyncComputed library for vue.js and by making a promise to download all images at once, instead of trying to do so individually.
/**
* Returns a promise that resolves when an item has all async properties set
*/
function VotingItem(item) {
var promise = new Promise(function(resolve, reject) {
item.short_description = item.description.slice(0, 140).concat('...');
if (item.image_loc === undefined) {
resolve(item);
}
firebase.storage().ref("items").child(item.image_loc).getDownloadURL()
.then(function(url) {
item.image_url = url;
resolve(item);
})
.catch(function(error) {
item.image_url = "https://placeholdit.imgix.net/~text?txtsize=33&txt=350%C3%97150&w=350&h=150";
resolve(item);
});
});
return promise;
}
var vue = new Vue({
el: '.barba-container',
data: {
items: [],
is_loading: false
},
firebase: function() {
return {
items: firebase.database().ref().child('items'),
};
},
asyncComputed: {
processedItems: {
get: function() {
var promises = this.items.map(VotingItem);
return Promise.all(promises);
},
default: []
}
}
});
Lastly, I needed to use: v-for="item in processedItems"
in my template to render the items with image urls attached