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>\LEADTOOLS23\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 that is 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 = async () => { 
   // Set the LEADTOOLS Evaluation license  
   const licenseUrl = "./Leadtools/LEADTOOLS.lic.txt";  
   const developerKey = "ADD THE CONTENTS OF THE LEADTOOLS.lic.key.txt FILE"; 
   lt.RasterSupport.setLicenseUri(licenseUrl, developerKey, null); 
   // Create the options object for the DocumentViewer  
   const 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  
   const url = "https://demo.leadtools.com/images/pdf/leadtools.pdf"; 
   const loadDocumentOptions = new lt.Document.LoadDocumentOptions(); 
   loadDocumentOptions.loadFormFieldsMode = 1; 
   // Call the "LoadFromUri" and pass success and failure callbacks to the promise  
   try { 
      let document = await lt.Document.DocumentFactory.loadFromUri(url, loadDocumentOptions) 
      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") 
      } 
   } catch (error) { 
      console.error(error); 
      // Get more information from LEADTOOLS  
      let serviceError = lt.Document.ServiceError.parseError(jqXHR, statusText, errorThrown); 
      lt.LTHelper.log(serviceError); 
 
      // Show an alert about what the issue is  
      let 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   
   const input = document.createElement('input'); 
   input.type = 'file'; 
   input.style.display = 'none'; 
   input.accept = '.doc, .docx, .pdf, .rtf, .txt'; 
   input.onchange = async function (e) { 
      let files = input.files; 
      if (!files?.length) 
         return; 
      let file = files[0]; 
      //Set the cursor to an idle animations  
      document.body.style.cursor = 'wait'; 
      //Create the document loading options  
      const loadDocumentOptions = new lt.Document.LoadDocumentOptions(); 
      loadDocumentOptions.loadFormFieldsMode = 1; 
      try { 
         //load the document from a file using the options  
         let doc = await lt.Document.DocumentFactory.loadFromFile(file, loadDocumentOptions) 
         //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") 
         } 
      } catch (error) { 
         console.error(error); 
      } 
      //return the cursor to default  
      document.body.style.cursor = 'default'; 
   }; 
   input.click(); 
} 
async function exportPDF() { 
   try { 
      //gets the document in the document viewer  
      let doc = await documentViewer.document; 
      //prepares the document for saving  
      documentViewer.prepareToSave(); 
      //saves the document to the cache  
      lt.Document.DocumentFactory.saveToCache(doc) 
      //once the doc is saved to the cache, creates the printing option  
      const 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); 
 
   } catch (error) { 
      console.error(error); 
   } 
} 

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() { 
   let doc = documentViewer.document; 
   documentViewer.prepareToSave(); 
   if (doc.formFields.hasFormFields) { 
      let 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>\LEADTOOLS23\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 23.0.2024.4.23
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2024 LEAD Technologies, Inc. All Rights Reserved.


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