Implement WebViewer with SQLite3 and XFDF to Enable Saving and Loading Annotations

In addition to showing how to add a WebViewer iFrame component to a Vanilla JS client app, this sample expands on annotation functionality by enabling the saving and loading of annotation objects into an SQLite3 database on the server side.

The saving and loading are done through GET and POST HTTP messages that are handled by an AnnotationController in the project. The annotations are stored as XFDF strings embedded in the messages and saved in the server-side database.

WebViewer provides a slick out-of-the-box responsive UI that enables you to view, annotate and manipulate PDFs and other document types inside any web project.

Click the button below to view the full project in GitHub.

1
2var viewerElement = document.getElementById('viewer');
3var DOCUMENT_ID = 'webviewer-demo-1';
4
5WebViewer.Iframe({
6 path: 'lib',
7 initialDoc: 'https://pdftron.s3.amazonaws.com/downloads/pl/demo.pdf',
8 documentXFDFRetriever: async () => {
9 const rows = await loadxfdfStrings(DOCUMENT_ID);
10 return JSON.parse(rows).map(row => row.xfdfString);
11 }
12}, viewerElement).then(instance => {
13 var docViewer = instance.Core.documentViewer;
14 var annotManager = docViewer.getAnnotationManager();
15
16 // Save when annotation change event is triggered (adding, modifying or deleting of annotations)
17 annotManager.addEventListener('annotationChanged', function(annots, action, options) {
18 // If the event is triggered by importing then it can be ignored
19 // This will happen when importing the initial annotations from the server or individual changes from other users
20 if (options.imported) return;
21
22 annotManager.exportAnnotationCommand().then(function (xfdfStrings) {
23 annots.forEach(function(annot) {
24 savexfdfString(DOCUMENT_ID, annot.Id, xfdfStrings);
25 });
26 });
27 });
28});
29
30// Make a POST request with document ID, annotation ID and XFDF string
31var savexfdfString = function(documentId, annotationId, xfdfString) {
32 return new Promise(function(resolve) {
33 fetch(`/server/annotationHandler.js?documentId=${documentId}`, {
34 method: 'POST',
35 body: JSON.stringify({
36 annotationId,
37 xfdfString
38 })
39 }).then(function(res) {
40 if (res.status === 200) {
41 resolve();
42 }
43 });
44 });
45};
46
47// Make a GET request to get XFDF string
48var loadxfdfStrings = function(documentId) {
49 return new Promise(function(resolve) {
50 fetch(`/server/annotationHandler.js?documentId=${documentId}`, {
51 method: 'GET'
52 }).then(function(res) {
53 if (res.status === 200) {
54 res.text().then(function(xfdfStrings) {
55 resolve(xfdfStrings);
56 });
57 }
58 });
59 });
60};
61

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales