Open Igal-Kleiner opened 4 years ago
Well, apparently there's some issue with vue-pdf library. Eventually I solved it by setting timeout when assigning fileName prop and re-rendering the component:
<PdfViewer v-if="selectedFileName" :fileName="selectedFileName" />
onFileNameSelected(fileName) {
this.selectedFileName = null
setTimeout(() => {
this.selectedFileName = fileName
}, 0)
}
And then in the PdfViewer component it's just:
created() {
this.src = pdf.createLoadingTask(this.getAttachments[this.fileName])
},
mounted() {
this.src.promise.then(pdf => {
this.numberOfPages = pdf.numPages
})
}
That did the trick for me, though feels kinda hacky. I think the library should support dynamic URL changes out of the box.
A short example using Composition API:
<template>
<section>
<p v-if="loading">
Loading...
</p>
<p v-else-if="error">
Error msg
</p>
<pdf
v-for="p in numPages"
:key="p"
else
:page="p"
:src="src"
/>
</section>
</template>
const loading = ref(true);
const error = ref(false);
const data: Ref<ArrayBuffer | undefined> = ref();
const numPages = ref(0);
const src = ref();
onMounted(async () => {
// Process download only if path includes our backend server base url
if (props.path.includes(API_BASE_URL)) {
const downloadUrl = props.path;
// Get blob from server
const blob = await reqBlob(downloadUrl);
// Convert binary blob to array buffer
data.value = await new Response(blob).arrayBuffer();
// Create file loading task
src.value = await pdf.createLoadingTask({ data: data.value }).promise;
// Set pages num
numPages.value = src.value.numPages;
// Unset loading state
loading.value = false;
} else {
error.value = true;
}
});
return {
loading,
error,
data,
src,
numPages,
};
I created the following component, PdfViewer, to which I pass a fileName as a prop. When the fileName is passed, it should look for the URL in the store getter and refresh the pdf component with the new pdf.
The first file is loaded OK, but when passing another fileName - the component doesn't refresh and I don't see the new file.
I discovered, that when the fileName changes and the init() method runs again after watcher, for some reason it skips the
loadingTask.promise.then
part. However, if I change back to the first fileName, that was already displayed, then it's being displayed again and the above code runs normally.I tried many possible solutions: create the component in the loop for every element in my getter object and then render it only if it matches the passed fileName, tried
this.src.destroyed()
both in beforeDestroy() life cycle and in the fileName watcher, tried to use this.$forceUpdate() after init() and many more... Nothing seems to be working.Is it a bug? Or is there a possible solution for that?