Auto-Identify Mandatory Fields
I am certain at some point in time you have had to fill-out some type of form on a website and the required fields were identified by an asterisk (*). This is a common way to communicate to a user which fields are mandatory and which ones aren’t.
This is a design pattern that the Form Guide Team adopted when they conceived the default Form Guide user experience. Since the appearance of a field in a form guide doesn’t have to be the same as that of the field in the form (PDF), they were able to automatically add an asterisk next to mandatory fields without affecting their PDF counterparts.
For example, in the following images, the Name and Address fields are mandatory (“Object palette > Value tab > Type property” is set to “User Entered – Required”) while the rest are optional. Notice how the captions of the Name and Address fields in the Form Guide have asterisks while the ones in the PDF don’t (and I didn’t have to do anything other than include those fields in a panel in a Form Guide in order to get this functionality):
— Form Guide
— PDF
Unfortunately, while XFA gives us the ability to mark a field as mandatory, Acrobat/Reader doesn’t automatically set them apart like the Form Guide does. Perhaps that’s a good thing because it gives you full control over how to identify fields as being mandatory.
Mandatory fields could be highlighted in different ways: An asterisk, a different background color or various other types of styles. If you use an asterisk, however, the tendency is to put it in the caption but doing this manually can be tedious if there are a lot of fields. What if some fields only become mandatory after certain conditions are met as the user is filling the form? If you don’t put the asterisk in the field’s caption (so that you can easily show/hide it when necessary using script), then you risk getting into various layout issues trying to get the asterisk to show-up at the right position next to each field. It also means lots more form objects which could really bloat your form.
That’s why I decided to implement a script that automatically adds the asterisk to a field’s caption. That way, you don’t have to worry about the asterisk — just mark the field as mandatory, run the script on initialization and it will search the entire form, placing a red asterisk in the captions of mandatory fields regardless of nesting levels. Furthermore, if you decide to use a text object as a caption next to a caption-less field or radio button list, the script will mark it with an asterisk as well (provided the text object’s name is the same as the field/radio button list’s but with a “_Caption” postfix).
Applying my script to the sample above would yield the following results in the PDF without affecting field appearances in the Form Guide:
— PDF
mandatoryLib
The following sample form references the auto-asterisk script in the mandatoryLib script object fragment. I suggest you download the fragment (see link below) and reference it in all the forms in which you want to use the script. Feel free to enhance it as well if it doesn’t work quite right for your particular needs: The script is heavily commented so it should be easy to follow and extend.
There are two functions you can call:
- IdentifyMandatoryFields(formObj): Given a form object (field or container such as radio button list or subform), find all mandatory fields inside (all nesting levels) and add an asterisk to their captions (actual captions or text object captions).
- ToggleMandatoryField(formObject, isMandatory): Given a field or radio button list, toggle its mandatory state by adding (isMandatory == true) or removing (isMandatory == false) the asterisk.
Furthermore, since the scripts handles both plain and rich text captions, you don’t have to worry about making sure all captions use rich text formatting.
Note about rich text: If you look at the script, you’ll notice that the rich text value of a field’s caption or text object’s content is retrieved from the Template DOM rather than the Form DOM. The Template DOM is where the design-time form object definitions are stored (it’s what you define when you edit the form in Designer) and cannot be modified at runtime (i.e. Acrobat/Reader) while the Form DOM, generated at runtime, is very sparse and contains only what is needed to render the form object in its current state. That means as long as there are no modifications to the rich text value, it will not appear in the Form DOM and must be retrieved from the Template DOM instead. One draw-back of this issue is that if you make any modifications to the caption/text object and then run the script, those modifications will be lost because the script will use the un-modified rich text from the Template DOM rather than your modifications stored in the Form DOM.
Download Sample [pdf] (if you plan on editing this Designer, you’ll also need the fragment below in the same folder)
Download mandatoryLib Fragment [xdp] (to download, right-click on the link and choose “Save Link As…”)
Special Thank You to my friends at Avoka for pointing-out that my original solution didn’t handle mandatory fields in repeating subform instances.
Sample Minimum Requirements: Since the script object uses dynamic object variables for optimization, I had to set it to use XFA 2.8 which means you’ll need Acrobat/Reader 9.0 to run it.
mandatoryLib Minimum Requirements: You could probably get away with running this script in an XFA 2.5 form (Acrobat/Reader 8.0), maybe even less, but the optimizations with the $formObjMap object may not function properly due to an aggressive JavaScript Garbage Collector in earlier versions (in other words, the script may run slower but it should still run).
Aug 28, 2009 — Separated mandatoryLib script object out into a script object fragment.
Posted by Stefan Cameron on March 16th, 2009
Filed under Acrobat,Form Guides,Scripting,Tutorials
Both comments and pings are currently closed.
When you say: “Acrobat/Reader doesn’t automatically set them apart like the Form Guide does” are you consciously excluding the Preferences>Form>”Required fields highlight color” Adobe Reader preference?
Not that I don’t love the way Adobe Reader marks mandatory fields :-). I surely prefer the * indication. Though, the client I’m working for, now, wants yet a different graphical indication of “requiredness”: a green bottom border.
As I looked through your JavaScript code I noticed the GetTemplateFormObj function. I confess, I didn’t try to understand it all the way. Because I think it is not possible, in general, to find the template node of a form node. Am I wrong? (If I were the xfa engine I could know…but I’m not in the middle of the merge process to grab a reference to the originating template node…so…)
I think the impossibility arises from the junction of dynamic form elements and of unnamed xfa nodes.
Together (and with the extremely dangerous SOM expressions scoping rules) they create ambiguous cases:
(Template DOM)
<subform name=”Foo”>
<subform>
<occur min=”0″ max=”-1″/>
</subform>
<subform />
…
(Form DOM)
The node with a somExpression of “Foo.#subform[0]”:
* is the first instance of the first child subform of “Foo”
or
* the static counterpart of the second child subform of “Foo”, when there are no instances of the first child
Duarte Cunha Leao,
I’m simply presenting another way to identify mandatory fields in a form in an automated way.
And I don’t agree that it’s “generally” not possible to find a template node for a given form node. In fact, my script — if you tried to understand it — does a pretty good job at this in most cases. The problem with your example is that the SOM expressions actually change depending on how many instances of the repeatable subform there are.
Let’s say we take your example and put a mandatory field in the non-repeatable subform, like this:
Assuming there are no other unnamed subforms prior to foo in the hierarchy, then if there were no instances of the repeatable subform, then mandatoryField’s SOM expression would be
and if you ran my code, it would not find mandatoryField’s template node because in the template DOM, mandatoryField’s SOM expression is
That being said, if you were to add a single instance of the repeatable subform, then mandatoryField’s SOM expression would change to
and my code would find its template node because of the way the unnamed nodes are now indexed. Adding more instances, however, would make the code break again.
It might be possible to fix this but I don’t think it would be worth the effort. What we would really need is a property, right off the form node, which is a reference to its template node.
In general, I would say it’s bad practice to work with any kind of unnamed nodes — especially if they’re repeatable subforms. You would have a really hard time finding the Instance Manager, for starters. If you don’t want them to affect data binding (since unnamed subforms don’t, by definition), then you should still give it a name but set its “Object palette > Binding tab > Default Binding property” to “None”.
Hi Stefan,
Thank you for the amazing form to toggle mandatory fields.
I started following your blog for last 2 months and you dont believe, I read all of your posts from archives and checked your sample forms.
I could not understand the necessity of this coding for mandatory fields form:
if (formObj.somExpression.indexOf(“xfa[0].form[0]”) != 0)
What exactly we are trying to find here on index? I checked the som expression and it returns xfa[0].form[0]. But I could not get why we used this if condition here.
I’m in the learning stage of javascript and my apologies if this is a kind a basics!!
Thank you,
Krishna
krishna,
Wow, I’m impressed!
Your question is very interesting. The reason behind the check for “xfa[0].form[0]” is that the function expects the formObj variable to be a form object located within the Form DOM as opposed to the Template DOM.
In an XFA form, there are many DOMs (Document Object Models). The 3 most important are the Template, Form and Data DOMs. The Template DOM defines the structure of the form and is defined at design time. The Form DOM is a runtime representation of the Template DOM (with overrides where appropriate depending on scripts, user interaction and data). Finally, the Data DOM is what contains the data (coming from XML, a database, a web service, etc.) that is merged with the Template DOM in order to produce the Form DOM.
The Form DOM is very sparse. In order to get the rich text captions for fields, we need to go to the Template DOM and find the pertaining field there in order to get its caption’s XHTML markup. Once that is found, we add/remove the asterisk and set the new value for the caption into the Form DOM’s version of the field, overriding the original definition and producing the new caption that the user sees.
Some of the methods in the mandatoryLib script object expect that a variable is in the Form DOM rather than the Template DOM. Looking at its SOM expression for “xfa[0].form[0]” as opposed to “xfa[0].template[0]” is one way of determining that we have what we’re expecting.
Hi Stefan,
Thanks for the reply. I’m amazed at you patience in replying to the comments. It was really helpful and now I got the actual funda behind the script and I could able to understand it easily.
I tried to dig more into form DOM and Data DOM like how actually the data is getting filled in the form DOM. I created a interactive student application form in form designer. The form is working fine and saved a PDF copy of it on my desktop. Now, I entered a student details into this PDF, and saved it. When I open the copy again, I can see my previously entered values in the PDF.
I was curious to know how the data we entered in the form got stored internally in this PDF. I tried to open this saved copy using designer to check and see these entered values in the xml source of the form. But none of the values (student details ) got stored anywhere.
Why is this like that. Where did all the entered values go when I open it in designer. Can’t we see the actual source of form DOM that happens in runtime?
I think there should be some confusion in my understanding of these things.
Regards,
Krishna
krishna,
You’re welcome.
The reason why you don’t see the saved data when you open the PDF form in Designer again is because XFA forms are stored inside PDF files. The PDF becomes a container for the form. When you open the form in Designer, you see the template design, not the actual template rendering.
When you open the PDF in Acrobat, you see the rendering (runtime) and you’ll also see any data that was previously entered and saved into that version of the PDF file. The data is stored in the form’s packet however, since this is runtime information only, you don’t see it at design time in Designer.
If you really want to see the Template, Form and Data DOMs in action, check-out this article by my colleague John Brinkman.
Hi Stefan,
Thanks for the reply. I’m amazed at you patience in replying to the comments. It was really helpful and now I got the actual funda behind the script and I could able to understand it easily.
I tried to dig more into form DOM and Data DOM like how actually the data is getting filled in the form DOM. I created a interactive student application form in form designer. The form is working fine and saved a PDF copy of it on my desktop. Now, I entered a student details into this PDF, and saved it. When I open the copy again, I can see my previously entered values in the PDF.
The Form DOM is very sparse. In order to get the rich text captions for fields, we need to go to the Template DOM and find the pertaining field there in order to get its caption’s XHTML markup. Once that is found, we add/remove the asterisk and set the new value for the caption into the Form DOM’s version of the field, overriding the original definition and producing the new caption that the user sees.
I could not understand the necessity of this coding for mandatory fields form:
if (formObj.somExpression.indexOf(”xfa[0].form[0]“) != 0)
What exactly we are trying to find here on index? I checked the som expression and it returns xfa[0].form[0]. But I could not get why we used this if condition here.
Uoi,
That IF condition tests to see if the formObj object is in the Form DOM since the solution, as a whole, deals with objects from both the Form DOM and Template DOM. In this particular case, we want to make sure we’re dealing with an object in the Form DOM. If the object was in the Template DOM, its SOM expression would start with “xfa[0].template[0]” instead.
Thank you for the amazing form to toggle mandatory fields.
I started following your blog for last 2 months and you dont believe, I read all of your posts from archives and checked your sample forms.
Holander,
Wow, that’s awesome! I’m glad you’re finding it useful. 🙂