A Form to Design a Form

There are a class of form designs where the form fill-in experience follows a basic pattern with a small number of variations.  A survey form is the prime example.  The variable pieces are the question text and a set of response types.  A user who wants to create one of these forms should not have to learn a complicated form design tool.  Given the relatively small number of properties that need to be specified to make a survey work, it should be possible to design a single dynamic form that can be shaped by any survey definition — i.e. one form that can render all variations of a survey.

We can design that survey form, but then we need to figure out an easy way for the author to define their survey.  This is really just another data capture problem — one that can be handled by a form.  So we use a form to design our survey.  A form to design a form.  Kind of like a play within a play.

To accomplish the form-within-a-form, there are two sets of data.  The survey-designer-form captures information for question text and response types and saves this information as its form data.  The fill-in-form has built-in variability (dynamic subforms) whose appearance and behaviour are customized from the data produced by the designer form.  The design data moves from being form data for the designer form to become metadata for the fill-in form.  When the fill-in version of the form runs, it produces its own data — the survey results.

Two Forms in One

Ideally, design and fill would be two separate forms.  But two separate forms means moving data between forms.  And even a relatively simple operation such as moving data is probably more than we can expect from our target users’ skill set.  As well, any multi-step process gets in the way of quickly previewing a survey.  To keep the experience as simple as possible, I’ve taken the approach of combining the design and fill-in experience into the same PDF.   The advantage is that the user deals with only one form and doesn’t have to manage their data.  There are likely better ways to do this.  If the experience were tethered to a server (LiveCycle for example :), it would be easier to manage the data on behalf of the user and keep the forms separate.  That would also make it easier to use a cool flash UI for the survey-design piece. 

But for now, to make the sample easy to distribute, I’ve combined them into one PDF.

Here’s the sample in several stages of processing:

An XFA form can fairly easily house two separate design experiences.  In my example, I had two optional top-level subforms: DesignSurvey and FillSurvey.  During survey design, the DesignSurvey subform exists.  During preview, DesignSurvey and FillSurvey both exist.  During fill-in, only the FillSurvey subform exists.  Which subform(s) appear is controlled by the form data and by script logic.

The Design mode allows you to create sections and question within sections.  The data to define a simple one-question survey looks like this:

<DefineSurvey> 
  <SurveyTitle>A survey about surveys</SurveyTitle>

  <ChoiceList>
    <ChoiceName>YesNo</ChoiceName>
    <Choice>
      <ChoiceText>Yes</ChoiceText>
      <Value>1</Value>
    </Choice>
    <Choice>
      <ChoiceText>No</ChoiceText>
      <Value>0</Value>
    </Choice>
  </ChoiceList>

  <Section>
    <SectionName>Personal Information</SectionName>

    <Question>
      <QuestionNumber>3</QuestionNumber>
      <QuestionText>Are you married?</QuestionText>
      <QuestionType>multipleChoice</QuestionType>
      <Required>0</Required>
      <ChoiceListName>YesNo</ChoiceListName>
      <MinSelections>0</MinSelections>
      <MaxSelections>1</MaxSelections>
    </Question>

  </Section>
</DefineSurvey

When designing the form, this data resides in the normal place for form data under:

<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
   <xfa:data>
      <DefineSurvey>…</DefineSurvey>
   </xfa:data>
</xfa:datasets>

When we switch to "fill-mode", we move the form definition (<DefineSurvey>) to a separate dataset and the fill-in data then lives under <xfa:data>:

<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
  <DefineSurvey>…</DefineSurvey>
  <xfa:data>
    <Survey>
      <Section>
        <Question>
          <QuestionNumber>3</QuestionNumber>
          <QuestionText>Are you married?</QuestionText>
          <Answer>1</Answer>
        </Question>
      </Section>
    </Survey>
  </xfa:data>
</xfa:datasets>

Once the form is in "fill mode", the PDF can be distributed to users.  Enable usage rights so they can save the results.  Or better yet, host your survey on acrobat.com.

Next Steps

The form design could expose more options. e.g. conditional logic, more response types, more constraints on responses, styling options.  It’s all just SMOP (small matter of programming). 

Submit

I added a submit button to the form in order to ret
urn the survey results.  There are a couple of things that are interesting about the handling of the submission. The survey definition includes a target email address.  The submit button gets updated with target and subject with this bit of code:

var vEmailTarget = "mailto:" + xfa.datasets.DefineSurvey.Email.value
                             +
"?subject=" + xfa.datasets.DefineSurvey.SurveyTitle.value;
EmailSubmit.event__click.submit.target = vEmailTarget;

The other thing I did with submit was make use of the new event cancel capability.  When the user clicks on the "submit" button, the pre-submit event fires.  I put this script there:

Survey.FillSurvey.#subform[2].EmailSubmit::preSubmit:form – (JavaScript, client)
if (scValidate.formHasErrors())
{
    scValidate.showErrors();
    xfa.host.messageBox("The survey is incomplete.  Please fill in the highlighted questions.");
    xfa.event.cancelAction = true;
    xfa.host.setFocus(scValidate.getFirstError());
}

The xfa.event.cancelAction property is new in Acrobat/Reader 9.  It allows you to cancel the upcoming action in prePrint, preSubmit, preExecute, preOpen, preSign events.

Validation Framework

The form makes extensive use of the validation framework I defined in previous blog entries — most notably, the exclusion group objects.  The framework is contained in the three script objects at the top of the form: scValidation, scGeneral and scGroup. These are re-usable objects that can be used in forms where you want fine-tuned control over the form validation experience.

For those who have used previous versions of this framework, I added some enhancements to suit my needs for this sample:

New function: scValidate.hideErrors()

After this is called, any fields with errors are not highlighted until…

New function: scValidate.showErrors(subform)

This function causes error fields that are descendents of the input subform to be highlighted.  If subform is omitted, errors are displayed on the entire form.

New function: getFirstError(subform)

Returns the first descendent field under the given subform that has an error.  It subform is not specified, returns the first error field on the whole form.

scGeneral.assignRichText(targetField, source)

Where targetField is a rich text field and the source is either a dataValue with rich text or another rich text field.

I also changed the code that highlights invalid fields.  Instead of mucking with borders, I simply set the fill colour.

13 Responses to A Form to Design a Form

  1. I updated the collateral for this post after I discovered a bug in the script.John

  2. Lorenzo Dee says:

    Hi John,Thank you sooo much for these blogs. It has made me look at XFA and dynamic PDF forms more. I’m just a beginner with XFA and LiveCycle Designer.Looking at the sample you have here, where there’s actually two forms: survey-designer-form and fill-in-form, would it be possible to create a dynamic form that follows a “wizard” like pattern?By “wizard” pattern, I’m referring to http://designinginterfaces.com/Wizard. This is where a user fills up a form by going through sections of the form and clicking on “next” and “back” buttons. Only a portion/section of the form is shown at a time.I would appreciate your inputs on this.Thanks

  3. Lorenzo:This is a very good question. It raises important issues.First of all… yes it is possible to turn your PDF form experience into a wizard.There is enough dynamism in XFA to support that. I’ve seen it done.You would likely design your form as a series of top-level subforms that represent panels in the wizard.Then you’d need script logic that makes one subform/panel visible and the rest hidden.But the more important question is: *should* you turn your form into a wizard?At the end of the day, PDF represents a paper metaphor. Using the tools designed to create a flowed paper representation to create a wizard might work — but it’s not what the tools were intended for.It probably isn’t the best experience for your users either. They’re used to seeing documents inside Reader — not panels. When they see the page count at the bottom of the screen, they may well be confused when it says “Page 1 of 1” — when they know they’re entering multiple “pages” worth of data.They want to be able to use file/print to get a print-out of their result. They want to be able to sign and certify what they see on the screen.These operations all break down when we move away from the paper metaphor.So what’s the alternative?- Use Flex/Flash- Deliver your wizard as an AIR application- If you’re a LiveCycle customer, you can use Form Guides.Each of these options require some investment on your part. It requires a more technical skillset to create a flash or AIR experience in Flex Builder. But there is strong payback for that investment.In my opinion, Adobe has more work to do in order to lower the effort for users to leverage these technologies.Your challenge is to provide an engaging user experience. The better crafted your form/wizard is, the higher the completion rates will be.As your web site notes, not every form ought to be a wizard, but when wizards are appropriate for your target audience, the extra investment to create the wizard will pay off.John

  4. An says:

    Hi John,Is there any way to make a form hide errors at first, and show errors when Email button has been pressed? I’m trying to use this form as a template, but when the fields are hidden at first, then shown when Email button has validated and returned errors, the unhighlight script stops working. Help?

  5. An:> but when the fields are hidden at firstDid you mean “errors hidden at first” ? or is there an issue with hidden fields? (I can’t think why that would cause a problem)The only reason I can think that highlighting/unhighlighting might fail is if you have added/removed subforms. When adding/removing subforms you need to call:scValidate.clearErrList();// remove subform herexfa.form.execValidate();If you don’t do this, some of the stored SOM expressions can get stale.John

  6. Jono Moore says:

    “I also changed the code that highlights invalid fields. Instead of mucking with borders, I simply set the fill colour.”Is there any way of adjusting this so there is some colour in the field if field highlighting is turned on? It does it on radio buttons, but not anything else (I’ve got some square radio buttons that show the highlight + the red colour).One advantage of the border method was that it was visible with field highlighting turned on. One disadvantage of the border method was that it would push the content slightly so when you exited the field the text would move a bit.

  7. Jono:It looks to me like field highlighting blends the highlighting color with your field color. I don’t know of any way to manage that blend…However, there are two things you can try:1) Highlight the entire field (not just the inner widget). To do this, set the fill on the outer border instead of the inner one. i.e. instead of:vObject.ui.oneOfChild.border.fill.color.value = “255,150,150”;try:vObject.border.fill.color.value = “255,150,150”;b) Turn off field highlighting. The command:app.runtimeHighlight = false;will turn it off.The border coloring is a bit wonky. I’ve seen what you’re describing. I suspect that turning edges visible/hidden can change the size of the object slightly.Hope this helps.John

  8. Jono Moore says:

    Thanks John, gave that a try and it does what I’d like to see – but it doesn’t colour the fields when highlighting is off.Guess it’s one or the other.I tried setting both in the script but it caused all sorts of mayhem. ;)

  9. Jono Moore says:

    I had another thought regarding visual feedback for fillers with regards to mandatory fields (whether a fix for you scripts or feature for upcoming new version).With the field highlighted red and highlight fields turned off, there’s no visual feedback as fillers tab through the form. It’s kind of difficult to see where the cursor is. Having the mandatory highlighting turn off as a filler enters the field might be nice.

  10. John Brinkman says:

    Jono:That’s a good suggestion. The only way I can think to do it is by changing the appearance with an “enter” (and “exit”) script. Placing this script on every field would be tedious — but easier to do with the event propagation in XFA 3.0 (Acrobat 9.1).John

  11. Rich says:

    This is pretty impressive stuff. Would it be possible to have the fields that have failed validation listed in a text field? I have tried to do this but have been unable to populate the text string with the name of the relevant fields.

  12. scott says:

    I’m sure this question has been asked alot of times, but when emailing the PDF using ‘mailto’, is it possible to name the PDF thats attached to the email. I’m actually surprised that the name of the PDF is some random list of numbers instead of the PDF filename.