Instance Manager Object Reference

It seems lately a lot of my posts and a lot of the comments that you’ve posted had something to do with the Instance Manager: The object available only on repeatable (dynamic) subforms which allows you to manage that subform’s instances (add, remove, etc.).

Since it’s at the core of repeatable subforms which are necessary when designing flowable (dynamic) forms that, say, display one row per record in a table connected to a database, I thought it would be useful to give a quick overview of the Instance Manager Object’s properties and methods.

Accessing the Instance Manager

Before we get to the properties and methods, here’s a refresher on how to get at the Instance Manager for a particular subform (or table row).

Repeatable Subform Required

First, you must make the subform repeatable. To make it repeatable, it must be placed in a flowed container — that is, another subform whose Content type (found on the Object palette’s Subform tab) is set to flowed.

Side Note: The simplest case is a report-style form that simply displays records from a database where each record’s information is displayed in separate fields within a subform. So you have a subform with fields in it that are bound to data nodes in some data connection and the subform itself is bound to a repeating data section in that same data connection. For this scenario, you’ll find it much easier to place your fields on the first page and then shrink the page (which is a subform) such that it’s snug against the fields you placed on it and looks more like a row rather than a page. This is because the page subforms are, by definition, subforms parented to the root subform (named "form1" by default on new forms — check it out at the top of the Hierarchy palette) and the root subform is, by definition, flowed. By using the page subform as your repeatable subform for your data records, you’ll find it much easier to quickly get to a state where all records show-up on your form and new pages get added when previous ones are full (can’t fit any more rows).

Once the subform is placed in a flowed container (parent subform), you must then specify that it’s a repeatable subform by going to the Binding tab on the Object palette and checking the "Repeat subform for each data item" box.

After these two easy steps are complete, you’ll then automagically get an Instance Manager object on the repeatable subform you just defined.

Script Access

It’s nice to have a repeatable subform but unless you’re just using the default behaviour (which may very well be just fine in most cases), you’ll need to write scripts that use it’s Instance Manager’s properties and methods and you’ll need to know how to access the Instance Manager in your scripts.

It turns out there are two ways of doing this:

  1. instanceManager Property: As long as you have at least one existing instance of the repeatable subform, you can access its instanceManager object directly like you would any other property: RepeatableSubform.instanceManager. Note, however, that this property will only be accessible if at least one instance of the RepeatableSubform object exists (which could be a problem if you’ve specified that its minimum allowed number of instances is zero and its initial instance count is zero as well).
  2. Underscore Prefix: The other recommended way to access a repeatable subform’s Instance Manager is to use, for lack of a better term, "the underscore-prefixed repeatable subform name" object. That is, whenever a subform becomes repeatable, its Instance Manager is added to the Script Object Model as a child of the subform’s parent container (remember, that’s the flowed subform from earlier) and is given a name that is the repeatable subform’s name with a "_" prefix. Therefore, if your subform was named "RepeatableSubform", its Instance Manager would get a name of "_RepeatableSubform" and you would access it as a property of the flowed container subform like this: FlowedContainerSubform._RepeatableSubform. The nice thing about accessing it this way is that you always have access to it — even if no instances of the RepeatableSubform object currently exist.

Properties and Methods

Now that you know how to make a subform repeatable and get access to its Instance Manager object when writing scripts, here are the various properties and methods that you have access to:

Properties

  • count: Returns the number of instances that currently exist. This is very useful when writing loops that do something to each instance.
  • min: Returns the minimum allowed number of instances. When removing instances, you’ll get a scripting error if the resulting number of instances is less than the minimum and the minimum number of instances will still remain (even if you meant to remove them). This can be set using the Min property on the Binding tab of the Object palette or my accessing the subform’s "occur" element and setting its min property: RepeatableSubform.occur.min = "value".
  • max: Returns the maximum allowed number of instances. When adding instances, you’ll get a scripting error if the resulting number of instances is more than the maximum and no additional instances will be added. You can modify this in the Object palette’s Binding tab or with the following property: RepeatableSubform.occur.max = "value".
  • occur: This is a reference to the pertaining subform’s <occur> element which lets you modify its minimum (min), maximum (max) and initial (initial) number of instances.
  • name: This property sets the name of the Instance Manager object itself. I doubt this would ever really be useful but it’s a property nonetheless. Be forewarned, however, that it’ll affect all subsequent scripts. For example, if you were to write "FlowedContainer._RepeatableSubform.name = ‘myIM’;" and then write "FlowedContainer._RepeatableSubform.addInstance(0);", you would get a an error stating that "_RepeatableSubform" doesn’t exist. That’s because you’ve changed its name to "myIM" and therefore should write "FlowedContainer.myIM.addInstance(0);".

Methods

  • addInstance(bool merge): Adds a new instance of the repeatable subform and returns a reference to the new instance (or null if no instance was added) . Setting merge to 1 will cause any additional data to be merged with the new instance. Also, don’t forget that new instances aren’t automatically added to the form’s calculation dependencies. Also, be careful not to add more than the maximum number of allowed instances (see the max property).
  • removeInstance(int index): Removes the instance with the specified zero-based index. Remember that if you’re running the form in Acrobat 7.x, you may need to call xfa.form.remerge() after removing an instance. Also, be careful not to remove more than the minimum number of allowed instance (see the min property).
  • moveInstance(int fromIndex, int toIndex): Moves the instance at the zero-based fromIndex such that it becomes the instance at the zero-based toIndex (and other instance in between are shifted up/down as necessary).
  • insertInstance(int position [, bool merge = 0]): [New in Acro 8.0] Inserts a new instance at the zero-based position specified and returns a reference to the new instance (or null if no instance was added). You may optionally specify 0 or 1 for the merge property which, if set to 1, will merge any additional data with the new instance. The same rules and gotchas apply for this method as they do for the addInstance method described above.
  • setInstances(int count): Adds or removes instances to/from the end of the set depending on the difference between the current instance count and the specified instance count. In other words, if there are currently 4 instances and you call "setInstances(6)", two new instances will be added to the end of the set. Conversely, if 3 instances exist and you call "setInstances(2)" the last instance in the set will be removed. Note that this method abides by the currently-specified min and max restrictions.

Recommended Scripting Language

On a last note, I simply wanted to recommend using JavaScript as opposed to FormCalc when scripting the Instance Manager — especially when adding or removing instances. While FormCalc technically fully supports the Instance Manager, I personally find it’s a little flakey. JavaScript support, however, is quite consistent and stable.


Updated: November 15, 2006

15 Responses to Instance Manager Object Reference

  1. chris surtees says:

    I have a form where users can enter a case number and click a button. The button then creates 3 subforms throughout the main form using addInstance(). In the first subform there is a button that says “Delete Section”. Once that is clicked I want all 3 subforms to be deleted. The user may have created a number of sections so I need to identify the correlating two sections.I thought I could just rename each subform based on the case number that the user entered and then reference each subform to be removed that way, but it doesn’t work.I can ‘apparently’ rename the subform, but when using the new name when using removeInstance() it doesn’t work.Test rename of subform:// this is in the initialization parameter of the field containing the policy numberthis.rawValue = “123”app.alert(this.parent.name); // provides the current subform name correctly.this.parent.name = this.rawValue; // should change the subform name to “123”app.alert(this.parent.name); // shows the value “123” which is what I would expect and wantBUTif I now click a button saying: ._123.removeInstance(0);it doesn’t work.If I now click a button saying: .OriginalFormName.removeInstance(0);it works.So it doesn’t appear that the subform name is really being changed at all. It’s a ruse :-(Any help would be great.

  2. Chris,When working with the Instance Manager (IM), it’s important to note that this object controls the instances of its pertaining repeatable subform which currently exist at runtime.When you add instances, you use the IM’s addInstance method and you must do the same when removing instances.For example, if you had a simple form with a repeating subform and two buttons: an “add” and a “delete” button. These buttons are outside the repeatable subform named “RepSF” (they’re siblings to it). The “add” button’s Click event would have JavaScript like this:

    _RepSF.addInstance(0);

    and the “delete” button’s Click event would have script like this:

    _RepSF.removeInstance(0);

    Based on your question, I think you’re probably following me at this point. I think where you’re going wrong is you’re expecting to call “removeInstance(0);” on the actual instance of a repeatable subform, which you’ve renamed, in order to remove it.Your attempt is definitely a logical one but it’s not quite how things work with the IM and since you need to make sure you only remove the instances that pertain to a specific policy number, you’ll need to use a different approach.I would recommend you use a hidden field inside the repeatable subform. Let’s call it “PolicyNumber”. When you add a new instance of that subform, you would do this:

    var oNew = _RepSF.addInstance(0);oNew.PolicyNumber.rawValue = “123”;

    Remember that the “addInstance” method returns a reference to the new instance so you can access the fields it contains just like you would a normal subform using that reference.Later, when the user clicks on the delete button, you would do something like this:

    for (var i = _RepSF.count; i >= 0; i–){  var oInstance = this.parent.resolveNode(“RepSF[” + i + “]”);  if (oInstance.PolicyNumber.rawValue == “123”)    _RepSF.removeInstance(i);}

    Note that the loop reverses through the instances because we’re removing some. Removing instances while looping forward through the set will get you in trouble because the “count” property will change on you and you’ll end-up walking over the edge of the array pretty fast.

  3. smvo says:

    Hi Stefan,There are some questions I would like to make relating to Instance Manager:1 – I know one can define at design-time a initial count to a repeated section, so that when the form open, the user will see that number of instances. But what about see those instance at design-time, also?2 – I´m truing to programmatically set values to fields in a repeating section using InstanceManager.If there is a previous instance (row) at design-time, because I´m adding additional instance my data was not being place at the first row. However I change my script and now it works.Then I set the initial count property to 2 and I realize the second row would never be filled with data, as if I write the first 2 rows values at the same instance. To set the values to these predefines instances I´m using:fldRegNodes.item(i).parent.ItemSet.nodes.item(auxinst) -> I think “item” will give me a reference to the “n” item in the field set, right?Thank you!

  4. smvo,I agree, being able to see the initial number of instances as defined by the min and/or initial properties at design-time would be very nice. Unfortunately, that’s not something that Designer is capable of doing at this time.In order to properly reference instances of subforms (whether they’re “plain” repeating subforms or they’re repeating rows in a table), you shouldn’t use the “nodes.item” method (since it doesn’t only iterate through child nodes but also child elements which are properties of the node itself).To do this properly, you should use the resolveNode method on the container of the repeating subform like this:var oItem = ItemSet.resolveNode(“RepeatingItem[” + i + “]”);The above JavaScript code will return a reference to the ith instance of the “RepeatingItem” subform inside the “ItemSet” container (e.g. replace “i” with “2” and you’ll get the 3rd instance since they’re zero-based).

  5. Raül Romero says:

    Hi Stefan.I have a problem related to the InstanceManager.I have a subform defined as a repeater. The data inside the repeater is bound to an XML schema.As a sibling of the repeater, there is a button to add a new instance. When it is clicked, I call the script “global.InvitedTowns._InvitedTownSubform.addInstance(1);”.The new instance is properly created but some of the data in the repeater is lost when I reopen the form.I could notice the following:1. The data lost is that of the complex subtype in the XML schema. That is, the repeater subform is bound to the element ” invitedTown[*]” of the XML schema. The simple elements inside there are properly kept; i.e. field “name”. But the field with an extra level of depth in the XML schema (those regarding the address of the town) are lost: “address.street”, “address.postalCode” and so on.2. The data of the first instance (default instance already existing when opening the form) is properly stored, also for the “address” details. However, the address data for the new instances created dynamically is lost after saving, closing and reopening the form.3. As a workaround, if I open an empty form, add all the needed instances (empty), save it and close it, I can properly fill in the data after reopening the form and nothing is lost afterwards.After all those tests, I guess there could be a bug related the dynamically generation of instances (maybe, memory management) and the binding of those dynamic instances with complex XML structures.Have you detected any similar problem or do you have any suggestion to solve it?Many thanks.

  6. Raul,This sounds like a data binding issue with the “address” schema node to me.I tried defining a little schema that had a repeating section named “invitedTown” with a nested complex section named “address” containing some more children. I was successful in creating a form with an “add” button that would let me add instances of the repeating subform representing the “invitedTown” node, enter some information, save the data, close the form, re-open the form and succesfully import the data I had previously saved. This would restore all data, including the data from the inner address section.I would suggest dragging and dropping the “invitedTown” node from the Data View palette onto a form, looking at the way the bindings are setup and trying to replicate that in your form in case one of your data bindings for an “address.?” node isn’t properly setup.

  7. Snehal Shah says:

    Hello Stefan,I am encountering some issues with either .instanceManager or _SubForm.addInstance.Basically, I have a form (FRM1 – Flow Content). I have sub form (FRM2 – Position Content, Repeat Subform for each data item, Min 1) in FRM1. Similar to the example you had. I also had one button to add instances of FRM2 dynamically and Email button to see XML. Only code I have is _FRM2.addInstance(1) on click event. When I do PDF Preview, and click on button, nothing happens. The form is not repeated. But when I check the saved XML, I can see two instances.I tried the sample from Adobe site http://blogs.adobe.com/formbuilder/samples/im/AddRecalculate.zip, that works but if I try to replicate this same example, no luck.Am I missing something here?Regards,Snehal

  8. Snehal,It sounds like you might either be previewing or have saved your form as a static PDF form. In that case, you won’t see new instances appear but they’ll be added to the data which explains the discrepancy between what you’re seeing on the form and what you’re getting in the submitted XML data file.I would recommend you check-out my article on previewing as dynamic PDF. It has tips on previewing and saving your form as a dynamic PDF form, which is what you’ll need to do in order to see the instances appear on your form in Acrobat.

  9. Snehal Shah says:

    Thanks Stefan,I did look at the properties and I made it work. With that working, I have two more question since I tried to implement a hypothetical example.In my example, I have to create instances of a subform on the fly, but place them randomly. So e.g. if I have PDF where I have following hierarchy.Page 1— General Info— Client1—— Personal Info—— Location Info—— Order Info— IMAGE FILLER SECTIONTotal InfoIn my General Info section, I have an option to say, “How many clients?” and “Per Client, How may products in the order?”.So Question 1 is,Using the dynamic instancing of subform for client section, can I create a form but place it say after IMAGE FILLER SECTION? I can create one after the other, but I want to have some other form or section in between two instances…And Question 2 is, after putting each Order Info page, there is a final total page which I want to show it at the bottom. Which ever page it is on, it has to be at the bottom. Using “Flow Content” layout, it always sticks to the bottom of last object. But I want it to have it at the very end.I tried quite a few tricks of using container area placement, overflow.. But got nowhere..Any help is sincerely appreciated. I am not sure, whether I shall post this question on Adobe forums or it looks at here.regards,Snehal Shah

  10. Snehal,For your first question, I think Designer’s Conditional Breaks feature might be able to solve this problem.You can use it to specify that an instance of the “IMAGE FILLER SECTION” should be placed after each instance of a “Client” section without necessarily causing a break to a new page. Simply define a conditional break set to “after” (the Break property), “No Break, Just Leader & Trailer” (the To property) and with its Trailer property set to the “IMAGE FILLER SECTION” subform.As for your second question, if you always want to show the “Total Info” section at the bottom of a new page, then all you need to do is place it at the bottom of its own page. Inserting instances of the other subforms in between will simply cause the page to automatically be pushed to the end. If, however, you want the section to always be placed at the bottom of an existing page, whatever page it may end-up on, that’s a different story which I don’t have an answer for.

  11. Michelle Yaras says:

    Stefan –Hopefully a quick question. I have a form where I use InstanceManager to repeat a subform (min. count 2). I would like to repeat a full page of the subform rather than just one subform at a time. I have not max limit set. Is there a way to do this? This form is used to submit a series of data about specific porducts so it is more than one line repeating.Thanks

  12. Snehal,A few days ago, I said I didn’t have an answer to your question about placing a particular subform at the bottom of the last page in a form.I did a little investigating and it turns out that there’s a way to achieve this but it’s not perfect. New features being released in the next version of Designer will make this possible in the “correct” way but for now, we have to deal with what we’ve got in Designer 8.0 or earlier.In order to demonstrate this and give you something to work with, I’ve posted a form which I believe resembles the type of form you’re trying to design.First, run it in Acrobat (7.0.5 or later), enter 2 for the client count and notice where the blue “total” subform ends-up: At the bottom of the first (and only page). That’s not difficult to do. Now, enter 3 as the client count and notice what happens: The first page isn’t quite long enough to fit the last “image filler section” so it overflows onto the next page and the “total” subform ends-up at the bottom of the second (last) page.If you check it out in Designer (7.1 or later), you’ll be able to see how it works:The Master Page named “Page1” contains two content areas which define where content (the subforms) will flow when the number of instances of the “client info” subform is modified.The root subform (named “form1” at the top of the Hierarchy palette) has a conditional break and an node set on it which specifies that its content should flow into the first content area named “ClientInfoCA”. Unfortunately, I had to specify these manually in the XML Source view since Designer doesn’t let you edit properties of the root subform in its palettes.The “ClientInfoSF” subform also has a conditional break to specify that the “ImageFillerSF” subform should be placed immediately after every instance of the ClientInfoSF subform. This ensures that the image filler section always appears after every client info section.The “TotalSF” subform has a conditional break which specifies that it should break to the “TotalCA” content area before it’s rendered on the form (which means it’ll always show-up in that content area which is located at the bottom of the page).Because the “TotalSF” subform is last in document order (or at the bottom of the hierarchy tree), Acrobat will only attempt to render it once it has finished rendering all prior instances of the “GeneralInfoSF”, “ClientInfoSF” and “ImageFillerSF” subforms, which means that it’ll only show-up once and it’ll always be at the bottom of the last page.The only draw-back to this design is that the two content areas can’t overlap or else the subforms may overlap in the rendered form. This means that you get an empty section at the bottom of every page before the last one where the “TotalCA” content area is located.If the “TotalCA” content area in your form is small enough, then this might be a viable option for you (the amount of blank space at the bottom of all pages prior to the last one might be negligible).I realize it’s a very complicated concept to explain in a comment on a blog so please don’t hesitate to ask more questions if there’s something you don’t understand.

  13. Michelle,I’m not certain I follow you when you say that you

    “would like to repeat a full page of the subform rather than just one subform at a time.”

    Are you saying that you would like to be able to determine the exact number of instances of this repeatable subform that fit on a page and show this number of instances initially, all in script when the form is loaded in Acrobat?Or are you simply asking how to specify an initial number of instances of this repeatable subform?Have you though about offering a field in which the person may specify the number of products for which they wish to provide data and then simply setting the number of instances to the specified count? This might get around the problem where you would provide too little or too many initial instances of the repeatable subform.

  14. krish says:

    Hi Stefan,I have a form where users can add subforms by clicking a “add_subform” button. when the subforms are added they are given subform numbers in increasing order.Each subform has a delete button which when pressed should delete the subform and re-order the subform numbers.how can i delete the subforms at runtime.what parameter is to be passed to the removeInstance(int) at runtime.

  15. Krish,The “removeInstance(int)” method is expecting the zero-based index of the instance of the subform which you wish to remove.If 4 subforms have been added and the user presses the “delete” button on the second subform, you need to call

    _ContainerSF.removeInstance(1);

    where “_ContainerSF” is the instance manager for the flowed subform which contains the instance of the subform that needs to be removed.You can get this index number by retrieve the index of the delete button’s parent object (which is the instance of the subform to be removed). From the delete button’s Click event, use this script:

    _ContainerSF.removeInstance(this.parent.index);