Load, Edit, and Export PDF Form Field Compatible PDF Files - HTML5 JavaScript

This tutorial shows how to load, edit, and save PDF files that are PDF Form Field compatible using the HTML5/JS Document Viewer.

Overview  
Summary This tutorial covers loading, editing, and exporting PDF form field compatible PDF files in a JavaScript application.
Completion Time 20 minutes
Visual Studio Project Download tutorial project (4 KB)
Platform JS Web Application
IDE Visual Studio Code - Client
Development License Download LEADTOOLS

Required Knowledge

Get familiar with the basic steps of creating a project and loading files into the Document Viewer by reviewing the Add References and Set a License - HTML5 JavaScript and Display Files in the Document Viewer - HTML5 JavaScript tutorials, before working on the Load, Edit, and Export PDF Form Field Compatible PDF Files - HTML5 JavaScript tutorial.

This tutorial makes use of http-server, a console command for running a static file server. To install http-server first install Node.js and then install http-server.

Create the Project and Add LEADTOOLS References

Start with a copy of the project created in the Display Files in the Document Viewer - HTML5 JavaScript tutorial. If that project is unavailable, follow the steps in that tutorial to create it.

The references needed depend upon the purpose of the project. References can be added by .js files located at <INSTALL_DIR>\LEADTOOLS22\Bin\JS.

For this project, the following references are needed:

Make sure to copy these files to the project's lib folder.

For a complete list of which JS files are required for your application, refer to Files to be Included with your Application.

Set the License File

The License unlocks the features needed for the project. It must be set before any toolkit function is called. For details including tutorials for different platforms, refer to Setting a Runtime License.

There are two types of runtime licenses:

Edit the HTML

With the project created, dependencies added, the license set, and the load file code added, coding can begin.

Open the index.html file located in the project folder and add the following lines in the .toolbar div:

<button class="button" id="loader">Load File</button> 
<button class="button" id="getData">Display Field Data in Console</button> 
<button class="button" id="export">Export PDF</button> 

Adding these buttons will allow the user to load PDF files, display the form field values, and export changes made to the PDF file.

Lastly, add this line above the ending </div> tag line in order to "house" our PDF file when exporting it:

<iframe id="parent"></iframe> 

The section should look like below:

<body> 
    <div class="container"> 
        <div class="toolbar"> 
            <button class="button" id="loader">Load File</button> 
            <button class="button" id="getData">Display Field Data in Console</button> 
            <button class="button" id="export">Export PDF</button> 
        </div> 
        <div class="docContainer"> 
            <div id="documentViewer"></div>     
        </div> 
        <iframe id="parent"></iframe> 
    </div>     
</body> 

Add the CSS styling to the CSS File

Open the styles.css file and add the following CSS styling.

/*   
   Remove default body styling.   
   Set the body to flex as a column;   
*/ 
body { 
   margin: 0; 
   display: flex; 
   flex-direction: column; 
} 
 
.container { 
   margin: 10px; 
   width: calc(100% - 20px); 
   height: calc(100vh - 20px); 
} 
 
.toolbar { 
   height: 5%; 
   width: 100%; 
   border-bottom: 2px solid #333; 
   display: block; 
   text-align: center; 
} 
 
.button { 
   padding-left: 2%; 
   padding-right: 2%; 
   width: 20%; 
   margin-right: 2%; 
   text-align: center; 
   height: 40px; 
} 
 
.docContainer { 
   height: 95%; 
   width: 100%; 
   display: flex; 
   flex-direction: row; 
} 
 
#documentViewer { 
   height: 95%; 
   width: 100%; 
   display: flex; 
   flex-direction: row; 
} 
 
#parent { 
   position: absolute; 
    left: -10000px; 
    width: 1px; 
    height: 1px; 
    overflow: hidden; 
} 
 
/* Styles for Elements Mode. */ 
.lt-item, 
.lt-image-border { 
   /* Box Shadow (view, item, image border) */ 
   box-shadow: #333 2px 2px 5px 1px; 
} 
 
.lt-view, 
.lt-thumb-item { 
   /* View */ 
   margin: 5px; 
   padding: 5px; 
} 
 
.lt-item { 
   /* Item */ 
   border: 2px solid #6ecaab; 
   background-color: #b2decf; 
   padding: 10px; 
} 
 
.lt-image-border { 
   /* Image Border */ 
   border: 3px solid #444; 
   background-color: white; 
} 
 
.lt-thumb-item { 
   /* Thumbnail Item */ 
   border: 2px solid #6ecaab; 
   background-color: #b2decf; 
} 
 
.lt-thumb-item.lt-thumb-item-selected { 
   /* Selected Thumbnail Item */ 
   border: 2px solid #59b2ba; 
   background-color: #8ce1e1; 
} 
 
.lt-thumb-item-hovered { 
   /* Hovered Thumbnail Item */ 
   border: 2px solid #52b996; 
   background-color: #87c7b1; 
} 
 
.small-modal { 
   max-width: 200px; 
   width: 200px; 
} 

Add the PDF Form Field Code to the JS File

Open the app.js file located in the project folder.

Be sure to have this first line at the top of the JS file so that the documentViewer object can be accessed:

let documentViewer = null;  

Add the code below to initialize the DocumentViewer object, set up connections to the document service, and also to enable the buttons for the tutorial. This will load a non-compatible PDF file initially.

window.onload = () => { 
   // Set the LEADTOOLS Evaluation license 
   lt.RasterSupport.setLicenseUri("https://demo.leadtools.com/licenses/js/LEADTOOLSEVAL.txt", "EVAL", null); 
   // Create the options object for the DocumentViewer 
   var createOptions = new lt.Document.Viewer.DocumentViewerCreateOptions(); 
   createOptions.viewCreateOptions.useElements = true; 
   // Set viewContainer to #documentViewer 
   createOptions.viewContainer = document.getElementById("documentViewer"); 
   // Create the document viewer 
   documentViewer = lt.Document.Viewer.DocumentViewerFactory.createDocumentViewer(createOptions); 
   // Set interactive mode to Pan / Zoom 
   //documentViewer.commands.run(lt.Document.Viewer.DocumentViewerCommands.interactivePanZoom); 
   // We prefer SVG viewing over Image viewing for this example 
   documentViewer.view.preferredItemType = lt.Document.Viewer.DocumentViewerItemType.svg; 
   // To use Image: lt.Document.Viewer.DocumentViewerItemType.image; 
   //documentViewer.view.imageViewer.autoCreateCanvas = true; 
   documentViewer.annotations.automationManager.renderingEngine = new lt.Annotations.Rendering.AnnHtml5RenderingEngine(); 
   // Initialize documentViewer annotations  
   documentViewer.annotations.initialize(); 
   // Before we call the service, we need to explain where it is ("localhost:40000/api", for example): 
   lt.Document.DocumentFactory.serviceHost = "http://localhost:40000"; // or wherever your host is 
   lt.Document.DocumentFactory.servicePath = ""; // the path to the root of the service, which is nothing for this example 
   lt.Document.DocumentFactory.serviceApiPath = "api"; // Routing occurs at "/api", unless you change the routing in the DocumentService 
   //Initialize the onclick events for our two buttons 
   document.getElementById('loader').onclick = selectAndLoadFile; 
   document.getElementById('getData').onclick = getData; 
   document.getElementById('export').onclick = exportPDF; 
   // Load a PDF document 
   var url = "https://demo.leadtools.com/images/pdf/leadtools.pdf"; 
   var loadDocumentOptions = new lt.Document.LoadDocumentOptions(); 
   loadDocumentOptions.loadFormFieldsMode = 1; 
   // Call the "LoadFromUri" and pass success and failure callbacks to the promise 
   lt.Document.DocumentFactory.loadFromUri(url, loadDocumentOptions) 
      .done((document) => { 
         documentViewer.setDocument(document); 
         if (document.formFields.hasFormFields) { 
            console.log("This document has PDF Form Fields. Click the 'Display Field Data in the Console' to see more information") 
         } else { 
            console.log("This document does not have PDF Form Fields") 
         } 
      }) 
      .fail((jqXHR, statusText, errorThrown) => { 
         // Get more information from LEADTOOLS 
         var serviceError = lt.Document.ServiceError.parseError(jqXHR, statusText, errorThrown); 
         lt.LTHelper.log(serviceError); 
 
         // Show an alert about what the issue is 
         var lines = []; 
         lines.push("Document Viewer Error:"); 
         lines.push(serviceError.message); 
         lines.push(serviceError.detail); 
         lines.push("See console for details.") 
         alert(lines.join("\n")); 
      }); 
} 

Next add two new functions named selectAndLoadFile and exportPDF which will be used to load a specified PDF file and export it when finished. Add the respective code below:

function selectAndLoadFile() { 
   //creates an input element on the Import Document button to upload files  
   //into the document editor  
   var input = document.createElement('input'); 
   input.type = 'file'; 
   input.style.display = 'none'; 
   input.accept = '.doc, .docx, .pdf, .rtf, .txt'; 
   input.onchange = function (e) { 
      var files = input.files; 
      if (!files || !files.length) 
         return; 
      var file = files[0]; 
      //Set the cursor to an idle animations 
      document.body.style.cursor = 'wait'; 
      //Create the document loading options 
      var loadDocumentOptions = new lt.Document.LoadDocumentOptions(); 
      loadDocumentOptions.loadFormFieldsMode = 1; 
      //load the document from a file using the options 
      lt.Document.DocumentFactory.loadFromFile(file, loadDocumentOptions) 
         .done((doc) => { 
            //set the new document in the document viewer 
            documentViewer.setDocument(doc); 
            //check to see if the document has form fields 
            if (doc.formFields.hasFormFields) { 
               console.log("This document has PDF Form Fields. Click the 'Display Field Data in the Console' to see more information") 
            } 
            else { 
               console.log("This document does not have PDF Form Fields") 
            } 
         }); 
      //return the cursor to default 
      document.body.style.cursor = 'default'; 
   }; 
   input.click(); 
} 
function exportPDF() { 
   //gets the document in the document viewer 
   var doc = documentViewer.document; 
   //prepares the document for saving 
   documentViewer.prepareToSave(); 
   //saves the document to the cache 
   lt.Document.DocumentFactory.saveToCache(doc) 
      .done(function () { 
         //once the doc is saved to the cache, creates the printing option 
         var options = new lt.Document.Viewer.PrintDocumentOptions(); 
         //certain printing options are being set 
         options.showAnnotations = true; 
         options.usePdfPrinting = true; 
         //gets the iframe HTMLElement that will "house" the printable pdf 
         options.parent = document.getElementById('parent'); 
         //prints and opens the browser printer for saving/printing 
         documentViewer.print(options); 
      }) 
} 

Lastly, add another function named getData which will display all the form field data to the console (this can be viewed in your browsers DevTools).

function getData() { 
   var doc = documentViewer.document; 
   documentViewer.prepareToSave(); 
   if (doc.formFields.hasFormFields) { 
      var containers = doc.formFields.getFormFields(); 
      for (let i = 0; i < containers.length; i++) { 
         for (let j = 0; j < containers[i].children.count; j++) { 
            console.log(`-------------------------- Page ${i + 1} - Field ${j + 1} ---------------------------------`) 
            console.log(`ID: ${containers[i].children.item(j).id}`); 
            console.log(`Name: ${containers[i].children.item(j).name}`); 
            console.log(`Bounds: ${containers[i].children.item(j).bounds}`); 
            console.log(`Background color: ${containers[i].children.item(j).backgroundColor}`); 
            console.log(`Printable: ${containers[i].children.item(j).printable}`); 
            console.log(`Viewable: ${containers[i].children.item(j).viewable}`); 
            console.log(`Locked: ${containers[i].children.item(j).locked}`); 
            console.log(`Required: ${containers[i].children.item(j).required}`); 
            console.log(`Read Only: ${containers[i].children.item(j).readOnly}`); 
            console.log(`Border Style: ${containers[i].children.item(j).borderStyle.style}`); 
            console.log(`Border Color: ${containers[i].children.item(j).borderStyle.color}`); 
            console.log(`Border Width: ${containers[i].children.item(j).borderStyle.width}`); 
            console.log(`Font Name: ${containers[i].children.item(j).textStyle.fontName}`); 
            console.log(`Font Size: ${containers[i].children.item(j).textStyle.fontSize}`); 
            console.log(`Font Color: ${containers[i].children.item(j).textStyle.color}`); 
            console.log(`Font Alignment: ${containers[i].children.item(j).textStyle.textAlignment}`); 
            console.log(`Type: ${containers[i].children.item(j).type}`); 
 
            if (containers[i].children.item(j).type == "DocumentTextFormField") { 
               console.log(`Value: ${containers[i].children.item(j).value}`) 
               console.log(`Content Type: ${containers[i].children.item(j).contentType}`); 
               console.log(`Max Length: ${containers[i].children.item(j).maxLength}`) 
               console.log(`Multi-Line: ${containers[i].children.item(j).multiline}`) 
               console.log(`Password: ${containers[i].children.item(j).isPassword}`) 
               console.log(`Comb: ${containers[i].children.item(j).isComb}`) 
            } 
            if (containers[i].children.item(j).type == "DocumentChoiceFormField") { 
               console.log(`Options Display Value: ${containers[i].children.item(j).optionsDisplayValue}`) 
               console.log(`Options Exported Value: ${containers[i].children.item(j).optionsExportedValue}`); 
               console.log(`Selected Indices: ${containers[i].children.item(j).selectedIndices}`) 
               console.log(`Multi-Select: ${containers[i].children.item(j).multiSelect}`) 
               console.log(`Choice Type: ${containers[i].children.item(j).choiceType}`) 
            } 
            if (containers[i].children.item(j).type == "DocumentButtonFormField") { 
               console.log(`Checked: ${containers[i].children.item(j).isChecked}`) 
               if (containers[i].children.item(j).buttonType == 0) { 
                  console.log(`Button Type: Check Box`); 
               } else { 
                  console.log(`Button Type: Radio Button`); 
               } 
            } 
         } 
      } 
 
   } 
   else { 
      console.log("This document does not have PDF Form Fields") 
   } 
} 

Run the Project

Before running the front-end HTML5/JS Document Viewer, you must run the Document Service. The LEADTOOLS SDK installation provides three examples of the Document Service for the following platforms:

For instructions on how to set up and configure the Document Service, in the three platforms previously listed, refer to the steps in the Get Started with the Document Viewer Demo - HTML5 JavaScript tutorial.

For the purposes of this tutorial, the .NET Framework Document Service is used and it can be found here: <INSTALL_DIR>\LEADTOOLS22\Examples\Document\JS\DocumentServiceDotNet\fx.

Once you have the back-end Document Service running, open the Command Line and cd into the project folder. Use the following command to run a static file server: http-server

The server should start and run on http://localhost:8080. A message should appear in the console indicating all the ports that the server is available on.

Screenshot of Http Server running.

To test, follow the steps below:

Wrap-up

This tutorial showed how to load, edit, and save a PDF form field compatible file in an HTML5/JS Document Viewer application.

See Also

Help Version 22.0.2022.6.24
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2022 LEAD Technologies, Inc. All Rights Reserved.


Products | Support | Contact Us | Intellectual Property Notices
© 1991-2022 LEAD Technologies, Inc. All Rights Reserved.