Last week I started to outline a design pattern for sharing data in a package. Again, the general problem we’re trying to solve is to allow multiple forms in a PDF package exchange data — where fields common to multiple forms is propagated. Part 1 of the problem is establishing a communication mechanism between documents. Once the documents have been disclosed to each other, any document in the package can modify any other document. Today’s Part 2 entry describes how to do the sharing.
Data mapping strategies
Implementing data sharing means solving a mapping problem: How do we know which fields in one PDF correlate to which fields in other PDFs? There are several techniques we could choose, including:
- Use the same name for common fields
- Generate a manifest that explicitly correlates fields
- Base all forms in the package on a common data schema
For my solution, I’ve chosen the 3rd option: common schema. The underlying assumptions are:
- Field values get propagated by assigning values in the data dom — a data value from one form will have the same data node address in each of the other forms
- The data dom in the package document will hold the aggregate data of all forms in the package — this is the ‘master copy’ of the data. Note that the package document does not have to have fields correlating to all the data elements.
- Attached forms will have their data synchronized from the master copy of the data when they are launched in Reader
Data Sharing Algorithm
With these assumptions in place, the actual algorithm is fairly simple:
- When any attachment opens, it registers with the package document
(the topic of Part 1)
- At registration, all data values of the attachment are synchronized from the master copy of the data in the package
- While the attachments are open, detect when field values change. The technique used to detect field value changes is to use propagating enter/exit events. We save the field value at field enter, and compare it to the result at field exit.
- When a field value changes, send a synchronize message to the package document.
- When the package document gets a synchronizing message, it updates the master copy of the data and then propagates the change to all other open attached PDFs.
One benefit of this approach is that the actual logic used to synchronize the data resides in the package document. This means you can customize your data sharing algorithm by modifying only the script in the package.
The really good news is that you can put this all together in a very simple design experience. With today’s sample, there are two fragment subforms: packageSync and embeddedSync. You can probably figure out where they each go. The fragment subforms have all the logic needed to register and synchronize the documents. They contain propagating enter/exit events so that all fields in the form are automatically synchronized. So the Design experience is as simple as:
- Drag the packageSync fragment on to a package subform
- Drag the embeddedSync fragment on each each attachment form
- Attach the embedded forms to the package form
Since the package document holds the aggregate of all the data, a global submit operation can be achieved by simply submitting the data from the package document.
There are some limits to the synchronization that you should be aware of:
- No handling for complex field value: rich text, images, multi-select choice lists
- Does not synchronize subform occurrences
- Does not synchronize calculated values
- Because we are relying on propagating events, the solution works only in Reader 9.1 or later
Each of these problems are solvable. I was just too lazy.
The sample form and all fragments are in this zip file. Try opening PackageSample.pdf and one or both attachments. Fill in fields and observe that they get propagated. Note that any field that has focus will not get updated until you exit the field.