Using the PDF Embed API With Vue.js
Getting more control of PDF experiences in the browser.
Join the DZone community and get the full member experience.
Join For FreeI've recently become acquainted with Adobe's PDF Embed API. As you can probably guess by the name, it's a library for embedded PDFs on a web page. It is not just a simple viewer; it has APIs for interacting with the PDF and excellent mobile support. This is a part of the Document Cloud service that provides other PDF tools (extraction, conversion, and so forth). I've been playing with the viewer a bit and wanted to see what Vue.js integration would look like. Here's my solution, but note that I'm still learning about the product, so it could probably be done better.
First off, to use the API, you need a key. Clicking the link from the webpage will walk you through generating a key. One important note on this, though. You have to lock down your key to a domain, and that domain cannot be changed either. Also, you can only specify one domain. So, if you want your domain and localhost, create two projects, generate two keys, and set them as environment variables for your development and production environment. I did my testing on CodePen and had to use this domain: cdpn.io
Once you have a key, you can copy the code from the Getting Started to test quickly. Here it is in its entirety, as it's pretty short:
<!--Get the samples from https://www.adobe.com/go/pdfembedapi_samples-->
<!DOCTYPE html>
<html>
<head>
<title>Adobe Document Services PDF Embed API Sample</title>
<meta charset="utf-8"/>
<meta data-fr-http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta id="viewport" name="viewport" content="width=device-width, initial-scale=1"/>
</head>
<body style="margin: 0px">
<div id="adobe-dc-view"></div>
</body>
</html>
Breaking this down, you listen for an event signifying that the library is loaded and then create a new "view" based on a div in your HTML. (In the example above, adobe-dc-view
.) Once that's done, you can use the previewFile
method to add the PDF viewer to the page. Here's a screenshot of this particular example:
Figure 1 Screenshot of example
I realize that the screenshot is small, but if you can't see it, the viewer includes the tools you would typically expect in Acrobat - navigation, search, and annotation tools. You can even save directly from the viewer and include your annotations. Here is my attempt at making life insurance documents more fun.
Figure 2 Example of Document
Cool. So as I said, it's a pretty powerful embedded viewer, and I want to play with it more later, but I first tried to add it to a simple Vue.js application. Here's how I did it.
First off, notice in the code listing above that we listen for an event on the document object, adobe_dc_view_sdk.ready
. For my code to work in Vue, I needed something more robust. An Adobian on the support forum noted that you could check for the window.AdobeDC
to see if the library is ready. I wrote my code such that the created
method of my Vue app can check that and still handle the library being loaded library. Broadly I did it by using a variable, pdfAPIReady
. My created
method does this:
JavaScript
1
created() {
2
//credit: https://community.adobe.com/t5/document-services-apis/adobe-dc-view-sdk-ready/m-p/11648022#M948
3
if(window.AdobeDC) this.pdfAPIReady = true;
4
},
And the final bit is a listener outside my Vue application. Remember that you can access the data
variable using the Vue instance. This is how I handled that:
// In theory I'm not needed on CodePen, but in the real world I would be.
document.addEventListener("adobe_dc_view_sdk.ready", () => { app.pdfAPIReady = true; });
In theory, my Vue app can make use of the library. The Adobe docs describe how to use local file content driven by an HTML input tag. Basically, you can pass a FileReader promise to the embed, and it will handle knowing when the local file is read and then rendered.
Here's the HTML I used for my demo:
<div id="app" v-cloak>
<strong>Select a PDF to Preview</strong>
<input type="file" accept="application/pdf" @change="previewPDF" ref="fileInput">
<h3 v-if="pdfSelected">PDF Preview:</h3>
<div id="pdf-view"></div>
</div>
Notice the pdfSelected
conditional. This is going to toggle after the user has selected a file. I originally had this in a div around the h3 and the div (pdf-view
), but the embed viewer didn't like its div being hidden by Vue. (I could probably change how I hide the div, but I'm leaving it for now.) Now for the JavaScript:
const ADOBE_KEY = 'b9151e8d6a0b4d798e0f8d7950efea91';
const app = new Vue({
el:'#app',
data:{
pdfAPIReady:false,
adobeDCView:null,
pdfSelected:false
},
created() {
//credit: https://community.adobe.com/t5/document-services-apis/adobe-dc-view-sdk-ready/m-p/11648022#M948
if(window.AdobeDC) this.pdfAPIReady = true;
},
methods: {
previewPDF() {
let files = this.$refs.fileInput.files;
if(files.length === 0) return;
this.pdfSelected = true;
let reader = new FileReader();
let viewer = this.adobeDCView;
console.log(`going to view ${files[0].name}`);
reader.onloadend = function(e) {
let filePromise = Promise.resolve(e.target.result);
viewer.previewFile({
content: { promise: filePromise },
metaData: { fileName: files[0].name }
});
};
reader.readAsArrayBuffer(files[0]);
}
},
watch: {
pdfAPIReady(val) {
// should only be called when true, but be sure
if(val) {
this.adobeDCView = new AdobeDC.View({
clientId: ADOBE_KEY,
divId: "pdf-view"
});
}
}
}
})
// In theory I'm not needed on CodePen, but in the real world I would be.
document.addEventListener("adobe_dc_view_sdk.ready", () => { app.pdfAPIReady = true; });
For the most part, all I did was use Adobe's example of reading a file and moving it inside a Vue method. The result lets you select a local PDF and have it rendered on my Vue app:
Figure 3 Example of a PDF
This is a relatively straightforward integration but hopefully helpful to folks wanting to use it with Vue. I've got some more examples coming! You can find the complete source code below.
const ADOBE_KEY = 'b9151e8d6a0b4d798e0f8d7950efea91';
const app = new Vue({
el:'#app',
data:{
pdfAPIReady:false,
adobeDCView:null,
pdfSelected:false
},
created() {
//credit: https://community.adobe.com/t5/document-services-apis/adobe-dc-view-sdk-ready/m-p/11648022#M948
if(window.AdobeDC) this.pdfAPIReady = true;
},
methods: {
previewPDF() {
console.log("lets do this!");
let files = this.$refs.fileInput.files;
if(files.length === 0) return;
this.pdfSelected = true;
let reader = new FileReader();
let viewer = this.adobeDCView;
console.log(`going to view ${files[0].name}`);
reader.onloadend = function(e) {
let filePromise = Promise.resolve(e.target.result);
viewer.previewFile({
content: { promise: filePromise },
metaData: { fileName: files[0].name }
});
};
reader.readAsArrayBuffer(files[0]);
}
},
watch: {
pdfAPIReady(val) {
// should only be called when true, but be sure
if(val) {
this.adobeDCView = new AdobeDC.View({
clientId: ADOBE_KEY,
divId: "pdf-view"
});
}
}
}
})
// In theory I'm not needed on CodePen, but in the real world I would be.
document.addEventListener("adobe_dc_view_sdk.ready", () => { app.pdfAPIReady = true; });
/*
adobeDCView.previewFile({
content: {
location: {url: "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf"}},
metaData: {fileName: "Bodea Brochure.pdf"}
});
*/
Published at DZone with permission of Raymond Camden, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments