Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

Instantiating Subforms at Runtime

Something that’s often desired, when working with dynamic forms, is to let the user specify, at run time (in Acrobat), how many lines of information are required to specify what they want.

The classic example is a Purchase Order form on which there are objects (usually buttons) which let you add and remove item lines from the section of the form which calculates the total cost of the order based on how many items are being ordered and the quantity and cost of each item.

In order to achieve this, the use of the Instance Manager is required. The Instance Manager is an object which exists only on repeatable subforms (this could be a subform which is parented to a flowed subform and set to repeat for each data item or it could be a row in a table — since rows and tables are, essentially, subforms). With this special object, you can modify the set of instances of a repeatable (dynamic) subform.

You can access the Instance Manager in two ways. The first is by accessing the object from the dynamic (repeatable) subform:

// append a new instance of DynSubform within its parent container
DynSubform.instanceManager.addInstance(true);

// ensure that the new instance is included in
//  subsequent calculations
xfa.form.recalculate(true);

The second is by using the shortcut “underscore” syntax (note that this syntax is supported if the form is rendered to PDF):

// remove the third instance (zero-based) of DynSubform
_DynSubform.removeInstance(2);

// work-around for Acrobat 7.x bug (reported) where number of
//  instances isn't properly updated after calling removeInstance
xfa.form.remerge();

The drawback to using the first syntax is that there must always be at least one instance of the dynamic subform which exists. If you have a form which must initially not have any instances of a particular dynamic subform, then you need to use the second syntax with the underscore since that special object is always “available” to you regardless of the current number of instances of the dynamic subform in question.

It’s also important to pay special attention to the minimum, maximum and initial number of instances of a dynamic subform. This is set on the Object palette’s Binding tab once you’ve specified that the subform is to Repeat for Each Data Item. The min and max limits must be repected at all times when using the Instance Manager. For example, if you set a min count of 1 and attempt to remove the last instance of a dynamic subform, an exception will be thrown which will result in a script error. You can check the current number of instances by using the Instance Manager’s count property and compare it to, for example,

// get the minimum number of instances that can be instantiated
_DynSubform.min

There are other things you can do with the Instance Manager such as setting the number of instances (using its setInstance(int) method), move instances around (using its moveInstance(int, int) method) etc. These are covered in detail in the Adobe XML Form Object Model Reference (located in the XML section). Check-out the Manipulating instances of a subform section on page 675.


Posted by Stefan Cameron on May 18th, 2006
Filed under Instance Manager, Scripting
You can leave a response, or trackback from your own site.

13 Responses to “Instantiating Subforms at Runtime”

  1. Manuel on December 1st, 2006

    Thanks! Your example form helped clear some questions I had. The LiveCycle Dev. Center is great, but your content here is definitely helpful.

  2. dave on December 2nd, 2006

    Where can I find help designing a form using a script to validate the date and apply the tax if the form is files after a certain day of the month. In other words, if it is past the 20th of the month, a 10% penalty is applied to the total.

  3. Stefan Cameron on December 4th, 2006

    Dave,

    You can achieve this simply by using the following JavaScript code in the total field’s Calculate script:

    var oToday = new Date();

    if (oToday.getDate() > 20)
      SubTotal.rawValue * 1.10;
    else
      SubTotal.rawValue;

    where “SubTotal.rawValue” either retrieves the sub total of the order or is the summation equation itself.

    This script sets the Total field’s value to 10% more if the current day of the month is greater than the 20th.

  4. Iulia on March 28th, 2007

    Hi Stefan,

    I have a question related to how we can save such a form (after it was filled by the user).

    If you design a form with Adobe Acrobat Professional there is a setting you can do to enable users to save the form (Advanced menu > Enable User Rights in Acrobat Reader). But since creating dynamic forms is only possible in LiveCycle Designer I cannot make the same setting and buying licenses of Acrobat Reader Extensions for all users is not an option.

    I tried to add a Submit button on the form which sends PDF (connected to an ASP.NET application). I click on it but nothing happens. I also tried to put a simple button which runs the following Javascript on mouse up:

    form1.#subform[0].Button1::mouseUp: - (JavaScript, client)

    // Saving the form is done at the application level, so you need to invoke the
    // Acrobat app model.
    App.executeMenuItem(”SaveAs”); // The end user will be prompted to specify a
    // file name.
    // However, you must save the form silently if the form needs to be certified
    // and the certificate must be trusted for privileged JavaScript.
    var mydoc = event.target;
    mydoc.saveAs();

    Nothing happens either.

    Can you tell me please if there is another solution? Please note I need to save the entire pdf, not only the data entered by the user.

    Thanks in advance,
    Iulia

  5. Stefan Cameron on March 30th, 2007

    Iulia,

    The command you’re referring to (”Advanced | Enable Usage Rights in Adobe Reader”) in Acrobat Pro 8.0 can still be used with dynamic forms created in Designer (you can even use an earlier version of Designer like 7.1 if you wish).

    Simply create the form in Designer, save it as a Dynamic PDF form and open it in Acrobat Pro 8.0. That command will then be available to you and you’ll be able to save the form with Usage Rights enabled (e.g. data save) such that the user will be able to save the entire PDF along with the data using the Adobe Reader.

  6. Iulia on April 2nd, 2007

    Hi Stefan,

    You are so right! Thank you very much.

    I succeeded to save the form using the Acrobat Reader “Save” button, but I now have another question: I wanted to add a “Save” button to the form and when it is clicked to hide it and save the form (with the “Save” button hidden).

    For starters, I tried to put app.execMenuItem(”Save”) on the button click event but again, nothing happens.

    Can you shed some light on this, too? And can you indicate a help file or something similar to describe the pdf form structure objects (like xfa)?

    Thank you,
    Iulia

  7. Iulia on April 3rd, 2007

    Hi,

    Never mind about the help file; I found it on
    http://partners.adobe.com/public/developer/en/xml/Adobe_XML_Form_Object_Model_Reference.pdf

    However, the question related to adding a Save button to the form still remains.

    Many thanks,
    Iulia

  8. Stefan Cameron on April 3rd, 2007

    Iulia,

    Unfortunately, I don’t think you’ll be able to save the form silently using a button on a form.

    The problem with a silent save (i.e. just “save” instead of “save as”) is that it’s a security risk to the person using the form since they don’t know that it’s happening.

    You can, however, trigger a “save as” action from a button like this (in JavaScript only):

    app.execMenuItem(”SaveAs”);

    If you want to hide the save button prior to the save, you would just need to add this line prior to executing the menu item:

    this.presence = “invisible”;

    You can find more information on app.execMenuItem and its restrictions in the JavaScript for Acrobat API Reference, page 120.

  9. Meng on October 1st, 2007

    Hi Stefan,

    I have established a database connection in my forms such that whenever an user selects a value from a drop-down list, all the related fields will be updated with corresponding data records from the database. Besides, data records in database will be updated whenever an exit event is triggered as users modify/edit field data.

    Since this solution is only possible when there’s a connection to the database (on-line), it would be much more convenient for my users to have an off-line version which enables them to input any data and save it locally before doing the update to database when they have access to database again.

    So i have tried to save the forms with populated values from the database. But when I open the pdf again all the data are gone. Why is this happening?

    Thanks in advance!

  10. Stefan Cameron on October 14th, 2007

    Meng,

    Sounds like a cool form you’ve put together!

    The only thing that comes to mind as to why the fields go blank when you open the form with saved data is that the data connection you’ve defined is being opened when the form is initialized (opened in Acrobat). If a connection to the database can’t be established, the resulting dataset is empty and that’s what gets merged into the form, resulting in the fields becoming empty as well.

    You may need to add a button or two on the form which users can use to control when data is retrieved from and sent to the database using the data connection. You could, for example, have a “retrieve” button whose Click event opens the data connection in order to get the data from the database. At that point, the user can save the form with the data and continue filling it offline. Later, when online again with the updated data, the user can click on the second button, the “update” button, and that can open the data connection in order to send the updated data to the database.

    Have a look at the various ODBC data connection articles in my Data Binding section for some examples of the various things you may need to do.

  11. CF on October 6th, 2008

    Hi Stefan,

    I am trying to cascade the values in a dropdown box based on the value selected in another dropdown box within a repeating sub-form. In my case, the repeating sub-form contains a group of address fields, include dropdown boxes for State and City. Once the user selects a State, I want to limit the list of selectable Cities. I was able to make it work with a script in the validate event of the State field, but only for the first instance of the sub-form. Even though the event is executed for new instances of the subform, I couldn’t manipulate the City list in the new instance. I have a feeling the solution has something to do with InstanceManager, but couldn’t find any examples of how this is done.

  12. Stefan Cameron on October 10th, 2008

    CF,

    The Validate event isn’t the right event to use for what you’re trying to do, which isn’t really a validation. What you should be doing is using the Change event in the State drop down list to look at the new selection and then add the appropriate items to the City drop down list. The following script is what you would put in the State field’s Change event, in JavaScript:

    var newSelection = this.boundItem(xfa.event.newText);
    City.clearItems(); // remove all city field items that may have already been added from a previous State selection
    switch (newSelection)
    {
        case "NY":
            City.addItem("New York");
            City.addItem("Other city");
            break;
    
        case "AZ":
            City.addItem("Phoenix");
            break;
    }

    You shouldn’t need to worry about the instances of the repeatable subform in order to get this to work in all the instances, assuming the State field selection is done by the user.

  13. BAJ on October 20th, 2008

    CF has the same issue I am. The instance Manager is not holding Focus on the row (or column) that the user is editing.

    If you have a row that is generated by the Manager and it has code for a cell tied to a method it will work on the first instance on the sub form.
    If rows are added using the Manager, the code will continue to reference the information contained that same first instance (row) instead of changing focuse to the current instance that is being edited.

    How do you tell the instance Manager that you are editing (x)row ?

Leave a Reply

Alternate Help: Unfortunately, I am not always able to keep track of older posts. Please feel free to continue discussions here or seek help at an Adobe Forum: Designer/Acrobat, Designer ES, Designer (v6-v8), Acrobat, Reader.

If you're including scripts: To make sure your script and comment are properly interpreted, please make sure you replace any less-than ("<") characters with their character code equivalent: "&lt;" (without the quotes). Otherwise, your script and comment will inadvertently be cut short.