|
Introduction
Ty Button's 15 Seconds article "Creating a PDF with ASP" does a good job of explaining the installation of the FDF Toolkit ActiveX version on your server and using the methods of the FDFApp object. Rather than repeat what has already been covered, I will just explain the handling of the most common form elements within a PDF Forms file and demonstrate the handling of a Forms Data Format (FDF) file in a real-world situation.
Download all the sample files for part II here: 010823.zip.
Getting Started
We will discuss everything covered in Part I, however, the FDF Toolkit's ActiveX version will be used. I will not go into any detail on retrieving data from a database, client-side or server-side validation, or getting the data back into a database. Everything discussed here will be relative to the form itself.
Everything discussed is HTML 4.01 compliant, compatible with ASP 2.0, Adobe Acrobat and Adobe Acrobat Reader 5.0, and FDF Toolkit ActiveX version 4. All code examples have been tested on a IIS 4 server with an IE 5.1 browser on the client.
Required Software
Adobe Acrobat 5.0 (the full version) is required by the form developer.
Adobe Acrobat Reader 5.0 is required by the client or user.
The FDF Toolkit ActiveX version must be installed on the server.
Step 1: Using the same FormTest.pdf file from Part I of this article, edit the Submit button's Submit Form Action URL to "FormTestFDFSubmit.asp." If you used the Import Data button, edit the Submit Form Action URL to "FormTestFDFSubmit.asp#FDF." Add a "Recommendation" FreeText area and three sets of two radio buttons named "radApprv1," "radApprv2," and "radApprvFinal." Label each set "Yes" and "No." Set the export value of each set to "Yes" and "No," respectively. Save the PDF as FormTestFDF.pdf. I have set the style to "Check."
Alternately, you can use my FormTestFDF.pdf file found in the complete downloadable source code. However, it would be wise to go through the trouble of modifying your own pdf.
Step 2: Create the front-end ASP that retrieves data from a database (if desired) and prepopulates all the fields in FormTestFDF.pdf. Name this file FormTestFDFImport.asp, and don't forget to specify your unique URL.
<%@ LANGUAGE = VBScript%>
<%
' SET UP YOUR PAGE
'***********************************************************************
Option Explicit
' DECLARE ALL THE VARIABLES
'***********************************************************************
Dim strFirstName ' First Name value for the txtFirstName field
Dim strProgExp ' Short description of programming experience
Dim strVBS ' Title for Program Language(s) most familiar w/-VBScript
Dim strC ' Title for Program Language(s) most familiar w/-C++
Dim strJava ' Title for Program Language(s) most familiar w/-Java
Dim strGender ' Gender of individual
Dim strFavSite ' Favorite Web site
Dim arrColors ' An array of HTML colors
Dim intFavColor ' Index of HTML colors array - Favorite
Dim i ' Counter used to iterate through arrColors
Dim FDFAcX ' FDF Toolkit ActiveX Version Object
Dim objFDF ' FDF Object
' SET UP YOUR CONNECTION OBJECT HERE
'************************************************************************
' SET UP YOUR RECORDSETS OR COMMAND OBJECTS HERE
'************************************************************************
' SET THE VARIABLES BASED ON DATABASE RESULTS
' (Here, I am setting them with literals as there is no actual database.)
'****************************************************************************
strFirstName = "Eric"
strProgExp = "9 months in HTML, 6 months in ASP & VBScript, 1 month in JavaScript, CSS2 & DOM"
strProgExp = strProgExp & " (Combination commonly referred to as DHTML)"
strVBS = "Yes"
strC = "No"
strJava = "No"
strGender = "Male"
strFavSite = "microsoft.com"
arrColors = Array("FFFF00", "000080", "DF0029", "666666", "009F62")
intFavColor = 1
' CLOSE & CLEAN UP YOUR RS, COMMAND OBJECTS, & CONNECTION OBJECT HERE
'**************************************************************************
' END DATA COLLECTION, CREATE THE FDF OBJECT HERE
'**********************************************************
Set FDFAcX = Server.CreateObject("FDFApp.FDFApp")
Set objFDF = FDFAcX.FDFCreate
' SET THE FULL ABSOLUTE URL OF YOUR PDF FILE
'*****************************************************
objFDF.FDFSetFile "http://Inetpub/wwwroot/PDF/FormTestFDF.pdf"
' USE THE FDFSetValue METHOD TO POPULATE THE PDF's FORM FIELDS
'*********************************************************************
' PDF form field name, Value you want entered, a value used to comply
' with Adobe Acrobat version 3.0 and below.
objFDF.FDFSetValue "txtFirstName", strFirstName, False
objFDF.FDFSetValue "txtExperience", strProgExp, False
objFDF.FDFSetValue "chkVBS", strVBS, False
objFDF.FDFSetValue "chkC", strC, False
objFDF.FDFSetValue "chkJava", strJava, False
objFDF.FDFSetValue "radGender", strGender, False
objFDF.FDFSetValue "selSite", strFavSite, False
' Loop through the arrColors array to populate the selColor drop down
' FDFSetOpt "Field Name", Option Index (Begins at 0), Export Value,
' Option Item Name
' Option Item Name is Null or Empty if there is no
' Export Value(Item Name will then equal the Export Value)
' Setting FDFSetOpt to "selColor", i, "#" & arrColors(i), "#" & arrColors(i)
' has exactly the same affect as below in the actual code. But,
' setting FDFSetOpt to "SelColor", i, i, "#" & arrColors(i) will
' appear normally, however
' the numeric value of i will be sent to the server when submitted.
For i = 0 to UBound(arrColors)
objFDF.FDFSetOpt "selColor", i, "#" & arrColors(i), ""
Next
' Set i to the indexed Favorite Color
i = intFavColor
' Select the Favorite color from the selColor drop down just populated above
objFDF.FDFSetValue "selColor", "#" & arrColors(i), False
' USE THE FDFSetStatus METHOD TO DISPLAY AN ALERT BOX
' (recommend that you don't, but it's cool that you can)
objFDF.FDFSetStatus "You must complete all sections of this form."
' WRITE THE ASSOCIATED VALUES INTO THE BUFFER STREAM AS AN FDF
Response.ContentType = "application/vnd.fdf"
Response.BinaryWrite objFDF.FDFSaveToBuf
' CLOSE YOUR FDF OBJECT AND CLEAN UP
objFDF.FDFClose
Set objFDF = Nothing
Set FDFAcX = Nothing
Response.End
%>
Step 3: Create the back-end ASP that collects the user's inputs and stores it to a database (if desired). Name this file as FormTestFDFSubmit.asp. Don't forget to specify the location where you want your FDF file saved and the hyperlink.
<%@ LANGUAGE = VBScript%>
<%
' SET UP YOUR PAGE
'********************************************************
Option Explicit
Response.Buffer = True
Response.Expires = -1441
' DECLARE ALL THE VARIABLES
'*********************************************************
Dim strFirstName ' First Name value for the txtFirstName field
Dim strProgExp ' Value of description of programming experience
Dim strVBS ' Value of Program Language(s) most familiar w/-VBScript
Dim strC ' Value of Program Language(s) most familiar w/-C++
Dim strJava ' Value of Program Language(s) most familiar w/-Java
Dim strGender ' Gender of individual
Dim strFavSite ' Favorite Web site
Dim strFavColor ' String of favorite HTML color
Dim i ' Counter used to iterate all field names
Dim FDFAcX ' FDF Toolkit ActiveX Version Object
Dim objFDF ' FDF Object
Dim strVersion ' FDF version number of this toolkit
Dim strColor ' Font color to compliment the favorite color
Dim strFormFileName ' PDF file name complete with the path
Dim strFld ' Temporary reference passed to the FDFNextFieldName method
Dim strFieldName ' Field Name extracted from the FDFNextFieldName method
Dim strFieldValue ' Field Value extracted from the FDFGetValue method
Dim intUserLevel ' User's position within a workplace environment
' INITIALIZE NECESSARY VARIABLES
'***********************************************************
' 0 = Requestor
' 1 = Requestor's immediate supervisor
' 2 = Level 1's supervisor
' 3 = Level 2's supervisor, has final authority
intUserLevel = 0 ' Normally this value would be extracted from
'a Session variable.
' BEGIN FORM DATA COLLECTION USING THE FDF OBJECT HERE
'************************************************************
Set FDFAcX = Server.CreateObject("FDFApp.FDFApp")
Set objFDF = FDFAcX.FDFOpenFromBuf (Request.BinaryRead(Request.TotalBytes))
' USE THE FDFGetValue METHOD TO COLLECT THE PDF's FORM FIELDS VALUES
' This is one method of collecting the field values.
'************************************************************
strFirstName = objFDF.FDFGetValue("txtFirstName")
strProgExp = objFDF.FDFGetValue("txtExperience")
strVBS = objFDF.FDFGetValue("chkVBS")
strC = objFDF.FDFGetValue("chkC")
strJava = objFDF.FDFGetValue("chkJava")
strGender = objFDF.FDFGetValue("radGender")
strFavSite = objFDF.FDFGetValue("selSite")
strFavColor = objFDF.FDFGetValue("selColor")
' Additional FDF information
strFormFileName = objFDF.FDFGetFile
strVersion = FDFAcX.FDFGetVersion
If strFavColor = "#FFFF00" OR strFavColor = "#FFCC00" Then
strColor = "black"
Else
strColor = "white"
End If
' SET UP YOUR CONNECTION OBJECT HERE
'**************************************************************
'SET UP YOUR RECORDSETS OR COMMAND OBJECTS HERE AND STORE THE
' ABOVE-EXTRACTED DATA
'****************************************************************
' CLOSE & CLEAN UP YOUR RECORDSETS, COMMAND OBJECTS,
'& CONNECTION OBJECT HERE
'****************************************************************
' DISPLAY THE ABOVE-EXTRACTED DATA
'****************************************************************
%>
<html>
<head>
<title>FormTestFDF.pdf Posted Results </title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body bgcolor="#FFFFFF">
<p>This will accept the data from FormTestFDF.pdf</p>
<!-- Provide a link using the actual saved FDF file (Saved below) -->
<p><a href="http://Inetpub/wwwroot/PDF/FormTestFDF.fdf">View this form again</a>
to demonstrate a User's Level (position) within a workplace environment.</p>
<table width="50%" border="1" cellspacing="5" cellpadding="5">
<tr>
<td>This is the value from the txtFirstName field:</td>
<td> <% = strFirstName %> </td>
</tr>
<tr>
<td>This is the value from the txtExperience field:</td>
<td> <% = strProgExp %> </td>
</tr>
<tr>
<td>This is the value from the chkVBS field:</td>
<td> <% = strVBS %> </td>
</tr>
<tr>
<td>This is the value from the chkC field:</td>
<td> <% = strC %> </td>
</tr>
<tr>
<td>This is the value from the chkJava field:</td>
<td> <% = strJava %> </td>
</tr>
<tr>
<td>This is the value from the radGender field:</td>
<td> <% = strGender %> </td>
</tr>
<tr>
<td>This is the value from the selSite field:</td>
<td> <% = strFavSite %> </td>
</tr>
<tr>
<td>This is the value from the selColor field:</td>
<td bgcolor="<% = strFavColor %>"><font color="<% = strColor %>">
<% = strFavColor %> </font></td>
</tr>
<tr>
<td>This FDF Version is:</td>.
<td> <% = strVersion %> </td>
</tr>
<tr>
<td>This PDF File Name is:</td>
<td> <% = strFormFileName %> </td>
</tr>
<%
' USE THE FDFNextFieldName METHOD TO COLLECT THE PDF's FORM FIELDS NAMES
' First field name is unknown so specify "".
' Store the name to a variable and pass it to your next FDFNextFieldName method
' Use the Field Name variable and pass it to the FDFGetValue method
' In this case the first field is the Submit button which has no value and
' returns an error if passed to the FDFGetValue method
' This is another method of collecting the field values
' but you must check for an empty value as there is no Length or Count property
' of the FDFNextFieldName
'*************************************************************************
strFld = objFDF.FDFNextFieldName("") 'Collect the first field name by passing ""
%>
<tr>
<td>Field0's name is:</font></td>
<td> <% = strFld %> </td>
</tr>
<%
i = 1
Do Until i = 0
strFieldName = objFDF.FDFNextFieldName(strFld)
If strFieldName & "" = "" Then 'Check for an empty value, end iteration if empty
i = 0
Else
strFieldValue = objFDF.FDFGetValue(strFieldName)
%>
<tr>
<td>Field<% = i %>'s name is:</font></td>
<td> <% = strFieldName %> </td>
<td> <% = strFieldValue %> </td>
</tr>
<%
strFld = strFieldName
i = i + 1
End If
Loop
%>
</table>
</body>
</html>
<%
' The object objFDF was initially set to equal all the FDF properties from
' the buffer during the FDFAcX.FDFOpenFromBuf method. So, not only can we
' read all of this data (which we have just shown), but we can modify it,
' add to it, subtract from it, or whatever, and save this new data as an FDF
' file. This is a physical file that can be processed later on or even
' attached to an e-mail and sent to a client.
'******************************************************************
' Let's say we have a request form that has multiple levels in a workplace
' environment. We can collect and identify a user via a session variable,
' and depending on what position the user holds in their company, we can choose
' to ignore or change form values that they have no business modifying. For
' instance, the originating user (the requestor) cannot recommend whether their
' request should be approved or not. So we would ignore or change these
' Recommendation blocks to the value of "Off."
' Let's also take into account that if a user does have the FINAL say
' in the matter but makes this determination based upon what their trusted
' subordinates have recommended. They would need to see what that actual
' subordinate recommended, not what
' their immediate subordinate may have changed these values to
'(FDF cannot modify a field's read-only attribute, unfortunately.).
Select Case intUserLevel
Case 0 '-- Requestor cannot make recommendations
objFDF.FDFSetValue "radApprv1", "Off", False
objFDF.FDFSetValue "radApprv2", "Off", False
objFDF.FDFSetValue "radApprvFinal", "Off", False
objFDF.FDFSetStatus "Requestor submitted this form, all recommendation blocks set to Off"
Case 1 '-- Level 1, can only make Level 1 recommendations
objFDF.FDFSetValue "radApprv2", "Off", False
objFDF.FDFSetValue "radApprvFinal", "Off", False
objFDF.FDFSetStatus "Level 1 submitted this form, only recommendation Level 1 was saved"
Case 2 '-- Level 2, can only make Level 2 recommendations
objFDF.FDFSetValue "radApprv1", "Yes", False ' Whatever was previously collected
' from Level 1 (We'll say 'Yes')
objFDF.FDFSetValue "radApprvFinal", "Off", False
objFDF.FDFSetStatus "Level 2 submitted this Form, only recommendation Level 2 was saved"
Case 3 '-- Level 3, has final authority
objFDF.FDFSetValue "radApprv1", "Yes", False 'Whatever was collected
objFDF.FDFSetValue "radApprv2", "Yes", False 'from Level 2 (We'll say 'Yes')
objFDF.FDFSetStatus "Level 3 submitted this form, only recommendation Level 3 was saved"
Case Else
'Normally we would place the FDFSavetoFile method in each case except this one.
End Select
'-- Save the collected data and any modified data to an FDF file.
objFDF.FDFSavetoFile "c:\Inetpub\wwwroot\PDF\FormTestFDF.fdf"
'-- CLOSE YOUR FDF OBJECT AND CLEAN UP --
objFDF.FDFClose
Set objFDF = Nothing
Set FDFAcX = Nothing
'-- The following causes the HTML to actually be sent to the client.
' Up to this point, no HTML has actually been downloaded to the client
' browser.
Response.End
%>
Conclusion
Ensure that you read the comments throughout the ASPs. They detail many of the FDF methods and various possibilities that may be implemented. Please experiment with the intUserLevel value in the FormTestFDFSubmit.asp file.
Unfortunately Adobe Acrobat Forms has a bug that causes the submission of a form to dump the user to a temporary local HTML document. There are two ways around this bug: Use a client-side script that redirects the user back to your server or provide an Exit button within the PDF form with the Action Type set to World Wide Web Link. (This simply provides an escape; you cannot collect any form data using this Action Type.) This was not included in the samples so that the submitted form data could be viewed.
Installing the FDF Toolkit -ActiveX version on your server and using the FDFApp object allows for much greater versatility than simply using the FDF text file within an ASP. As the samples have shown, you can save a FDF file and transport this file by any means. A saved FDF file is specifically associated with a PDF file on your server so that no matter where the FDF file is accessed from, it will resolve back to your server (unless your server is an intranet site and the user accesses the FDF file from outside of this environment). There are many more FDFApp methods that were not covered here. Also, there are quite a few additional FDFApp methods that only apply to a saved FDF file that will not work with an FDF object obtained from a submitted PDF form. (But, you can save the FDF submitted from a PDF form, close the object, and reopen the object with the saved FDF file, process some additional modifications, and save over the FDF file, all within the same ASP.)
Part III deals with the appearance of a form when viewed within a browser and changing this appearance when printing the form using DHTML (JavaScript, Cascading Style Sheets Level 2 [CSS2], and the Document Object Model [DOM]).
Resources
For an article on "How to populate a PDF file's form with data from a web server,"see
http://www.planetpdf.com/mainpage.asp?webpageid=370.
For an FDF Toolkit Overview, see
http://partners.adobe.com/asn/developer/acrosdk/docs/fdftk/FDFToolkitOverview.pdf.
For an FDF Toolkit Reference, see
http://partners.adobe.com/asn/developer/acrosdk/docs/fdftk/FDFToolkitReference.pdf.
The FDF Toolkit SDK can be obtained for free at http://partners.adobe.com/asn/developer/acrosdk/forms.html.
Note: This article covers FDF Toolkit version 4, whereas Adobe's current version is 5. They appear to be compatible.
About the Author
Eric Coffman is currently working as an ASP (mostly!) programmer for SIMA San Diego's Web Development and Information Systems. Adobe Acrobat PDF forms are used to automatically route various requests through a user's specific chain of command within an intranet environment. He can be contacted at komodo@backpacker.com.
|