I have a multi-file input object "files" and I want to generate preview blob. The previews object is correct, however doing files.value.map does not work. I want to attach the blob to the "files" object. What am I missing?
const files = ref([])
const previews = ref([])
const toBlob = async(file) => {
const buffer = await file.arrayBuffer()
const blob = new Blob([buffer])
const srcBlob = URL.createObjectURL(blob)
return srcBlob
}
watch(files, async() => {
previews.value = await Promise.all(
files.value.map((file) => toBlob(file))
)
await Promise.all(files.value.map(async(file) => {
console.log(file)
file.preview = await toBlob(file)
}))
})
return {
files,
previews
}
This is blank in the vue template. console.log is correct however.
<span v-for="file in files" :key="file">{{file.preview}}</span>
This is correct, showing the preview blob:
<span v-for="preview in previews" :key="preview">{{preview}}</span>
By passing an async function to files.value.map, you're getting an array of Promises. You can't await this array directly, because you can only await a Promise.
Instead, you can use Promise.all to turn an array of Promises into a Promise of an array:
await Promise.all(files.value.map(async(file) => {
console.log(file)
file.preview = await toBlob(file)
}))
I'm pretty sure the assignment of file.preview breaks the reactivity. You could try this in Vue3:
let { preview } = toRefs(file)
preview.value = await toBlob(file)
References:
It doesn't look like you actually need to attach a .preview property to the File object, since you already store them in previews[], so just remove that code:
watch(files, async() => {
previews.value = await Promise.all(
files.value.map((file) => toBlob(file))
)
// xxx: remove
//await Promise.all(files.value.map(async(file) => {
// console.log(file)
// file.preview = await toBlob(file)
//}))
})
The object URLs would not be rendered as images with string interpolation (i.e., between curly bracket pairs). That is, {{previewObjectUrl}} would only render the URL as a string.
To render the blobs, the object URLs must be bound to an <img>.src:
<img v-for="preview in previews" :key="preview" :src="preview">