1

I'm trying to load a multipage pdf from an API into vue.js using the vue-pdf library.

I have can successfully load the pdf and render the 1st page as described in this earlier question here

I've followed the instructions given in The Documentation and tried a with / without using a loadingTask and using different options for the number of pages.

I've attached the code below. this version shows no page number and no pdf. The console has the "loadPdf called" and "success" log messages and no errors.

<template>
  <div>
    <h3>page count is {{ numPages }}</h3>
    <pdf v-for="i in numPages" :key="i" :page="i" :src="pdfsrc"></pdf>
  </div>
</template>

<script>
import pdf from "vue-pdf";
import axios from "axios";
import ActiveDirectoryService from "@/services/ActiveDirectoryService.js";

export default {
  components: {
    pdf
  },
  props: {
    exportId: String
  },

  data() {
    return {
      pdfsrc: null,
      numPages: null,
      objectUrl: null
    };
  },
  mounted() {
    if (this.pdfsrc === null) return;
    this.pdfsrc.promise.then(pdf => {
      this.numPages = pdf.numPages;
    });
  },
  methods: {
    loadPdf() {
      console.log("loadPdf called");
      return axios
        .get(`${process.env.VUE_APP_API_INTRANET}/pdf`, {
          responseType: "blob"
        })
        .then(response => {
          console.log("Success", response);

          const blob = new Blob([response.data]);
          const objectUrl = URL.createObjectURL(blob);
          this.pdfsrc = pdf.createLoadingTask(objectUrl);
        })
        .catch(console.error); //
    },
    clearBuffer() {
      if (this.objectUrl !== null) {
        URL.revokeObjectURL(this.objectUrl);
        this.pdfsrc = null;
        this.objectUrl = null;
      }
    }
  },

  watch: {
    exportId: function(oldVal, newVal) {
      console.log("id Changed api for pdf.");
      this.loadPdf();
    }
  },
  created() {
    console.log("created with id ", this.exportId);
    this.loadPdf();
  },
  beforeDestroy() {
    this.clearBuffer();
  }
};
</script>

<style scoped></style>

I'm testing with a small 3 page pdf at 46kb in total. The closest I have come to getting this to work is to hard code the number of pages to 3 which renders the pdf correctly. eg

   <pdf v-for="i in 3" :key="i" :page="i" :src="pdfsrc"></pdf>

It works but obviously not a solution!

I've also tried other ways to load 'numPages' such as adding this to pdf

@num-pages="numPages = $event"

and using a computed that returns this.pdf.numPages

but so far all have failed.

I've also tried moving the promise to get numpages into the loadPdf method like so

   .then(response => {
          console.log("Success", response);

          const blob = new Blob([response.data]);
          const objectUrl = URL.createObjectURL(blob);
          this.pdfsrc = pdf.createLoadingTask(objectUrl);
          this.pdfsrc.promise.then(pdf => {
            this.numPages = pdf.numPages;
          });
        })
        .catch(console.error); //

which also doesn't work.


Update


I've peppered the code with log statements as requested. All looks like it should be working.

       .then(response => {
          console.log("Success", response);

          const blob = new Blob([response.data]);
          const objectUrl = URL.createObjectURL(blob);
          this.pdfsrc = pdf.createLoadingTask(objectUrl);
          console.log("this.pdfsrc.promise", this.pdfsrc.promise);
          this.pdfsrc.promise.then(pdf => {
            console.log("pdf in callback", pdf);
            this.numPages = pdf.numPages;
            console.log(
              `this.numPages: ${this.numPages} pdf.numPages: ${pdf.numPages} `
            );
            console.log(this);
          });
        })

Contents of log looks normal


Update 2

I've cleaned up my example and upon removing this line

@num-pages="numPages = $event"

from the template it all started working! I've traced back through the changes in code and it seems that wrapping the object url in a loadingTask and moving the promise to the loadPdf() method is what fixed it.

Twisted
  • 2,939
  • 4
  • 32
  • 54
  • you only set numPages in mounted and only when pdfsrc exists? guess thats your issue – Estradiaz Dec 14 '20 at 15:50
  • i've tried to move the .promise.then ().... code to the point at where the loading task is created but didn't fix it. The mounted() code is lifted from the documentation I linked. ut agree its probabilly something to do with the timing. – Twisted Dec 14 '20 at 15:53
  • the axios response is stacked via microtask, i guess, thus comes after mounted. Thus no race. Try to make a method updateNumPages and call it after loadPdf resolved? also maybe use a number instead null -> numPages: 0 instead null – Estradiaz Dec 14 '20 at 16:01
  • not sure how to hook into when the pdf has finished loading to get the number of pages. The promise to load the data resolves before the pdf has finished rendering. and chaining on to pdf.createLoadingTask didn't work when I tried earlier – Twisted Dec 14 '20 at 16:05
  • shouldnt it be somewhere here: `pdf.createLoadingTask(...).promise.then(done => ...)` ? – Estradiaz Dec 14 '20 at 16:10

0 Answers0