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:
- 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).
- 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
Posted by Stefan Cameron on November 11th, 2006
Filed under Instance Manager, Scripting
You can skip to the end and leave a response. Pinging is currently not allowed.


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 number
this.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 want
BUT
if 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.
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:
and the “delete” button’s Click event would have script like this:
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:
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:
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.
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!
smvo,
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).
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.
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.
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
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.
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 SECTION
Total Info
In 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
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.
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
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 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.
Michelle,
I’m not certain I follow you when you say that you
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.
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.
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
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:
Stefan,
Scripting and instance manager are totally new to me, so any assistance would be greatly appreciated.
Question on referencing instances. I have a 2 page form. The first page is a summary table and the second page provides details. So, I have it that I can add (and remove) instances on the summary table. This correspondingly adds pages to the document. Ideally, the way this should work is that the user adds a row in the summary, enters some summary information in the instance that is created and when he/she goes to the corresponding details page, the summary information has auto populated on that page as well (making it easy to find). For example, the first row of the summary table has an Item labelled #1, and in the detail pages, there is a page with a field that has #1 in it as well. So, there is a 1 to 1 relationship between the summary row and a details page.
Now the question is, how do I push the data in the fields from the summary table instance to the fields in the corresponding details page instance? I can’t figure out how to find and reference the fields in each instance of the subforms so that I can get them to equal each other.
Thanks in advance for any insights to can provide!
MK,
The important detail to note about the addInstance method of the Instance Manager is that it returns a reference to the new instance. That means that when you add a new page to your form (after adding a new row), you get a reference to that new page which you can then use to populate fields that it contains.
In your particular situation, you need to pass information from fields within a row in the summary table to fields on a detail page within your form. What you could do is use a script object which contains a variable to which you assign the new instance of the detail page that’s associated with the summary row that gets added. Putting the reference in a script object will let you “remember” what that instance was as the filler proceeds to fill the fields in the summary row. Then, each field would have a script on its Exit event which would refer to the variable in the script object and use it to access the pertaining fields in the detail page it references in order to set values (each field sets the pertaining detail page field’s value).
You can create a script object simply by right-clicking on the root subform (usually named “form1″) in the Hierarchy palette and choosing the “Insert Script Object” command. You then create a variable simply by declaring it like this:
And you assign it a value like this (likely from a button you use to add a new summary row and detail page, assuming you named the script object, “MyScriptObj”):
Now this is an extremely simple implementation which may already have few usability flaws depending on how elaborate your form is. For instance, can the filler change the summary information on the associated detail page and, if so, do those changes have to be replicated back to the pertaining summary row? If that’s the case, then you need to synchronize the fields on the summary row with the fields on the detail page and this gets more complicated. Here’s a hint: You could use an 2D array as your script object variable in order to associate a summary row reference with a detail page reference. The array would associate an index with an array of two object references such that the index of the detail page or summary row would correspond with the index in the array which is associated with the sub-array that contains the references to the other object. I’m happy to elaborate on this if it’s what you would like to do.
Hi Stefan,
Thanks for the help on this, it is greatly appreciated! Please pardon my lack of knowledge on this subject matter and my (probably) very basic questions. I’ve followed what you have advised above - I’ve created a script object (InstanceCnt) within which I have declared the following:
var oDetailPageRef = null;
In my “add instance” button, I have added the following code:
InstanceCnt.oDetailPageRef = _page2.addInstance(0);
To double check that the oDetailPageRef variable is getting populated, I outputted the variable value to the console and got the following:
[object XFAObject] (Which I assume is correct).
Now, just to show my lack of experience and knowledge, I’m stuck at how to reference the variable to populate the fields (referencing things seems to be my nemesis). You state in your previous answer that “each field would have a script on its Exit event which would refer to the variable in the script object and use it to access the pertaining fields in the detail page it references in order to set values…”.
As a result, I’ve tried to reference the variable a number of ways and keep getting an error stating that what I have referenced has no properties. So, I’m guessing that I am not correctly referencing the variable and associated field in the details page in order to set its value to the corresponding field in the summary table. What is the proper syntax to accomplish this?
Thanks again for the help!
As a followup to the second half of your response to my original question, I would be very interested in how to synchronize the forms more closely. I’m not sure that I have the technical abilities yet to incorporate it into my form (see my previous post), but at the same time new insights are always a good thing to learn…
Thanks.
MK,
It looks like you’re off to a good start. Before we takle synchronization between the summary rows and detail pages, let’s concentrate on getting the detail pages populated with the summary rows (one way).
What I’m thinking is that each field in the summary row would have JavaScript like this on their Exit events (which get executed when the focus leaves the field — when you tab out or hit the Enter key):
where {FieldName} is the name of the field within the detail page whose value should get the same value as the field into which the user has entered a value.
Let me know how you do with this. Hopefully it works and we can proceed to the synchronization.
Stefan,
Thanks again - this site is great! Okay, in the interim, I started playing around with some advice you had given another user, along with the advice you’ve given me. In the process I noticed something wierd - Acrobat gives me the “no properties” error when I reference (just as you showed above) the variable if I am referencing off of the container that has “Flow Content” (i.e., page 2). However, if I put a subform on page 2 of the same size as the margins, put my content there, and have that subform called by the instance manager - the referencing works beautifully. I’m not sure I explained that correctly - so let me show you my code:
1. I added a field asking for how many instances I want (TextField1)
2. On that field’s exit, I put the following code:
var j = TextField1.rawValue
_summary.setInstances(j)
page2._Details.setInstances(j) // you’ll note that I’m not increasing the number of instances for page 2, but for a subform in page 2
for (var i = 0; i
MK,
Could you re-post your last comment? Some of your script got cut-off and I’m having difficulties understanding exactly what you’re trying to do without proper context.
Hi Stefan, I have a little challenging task my work gave me, I work at a church and they wanted a new registration form and wanted to do it in .pdf. I have already created the form, but I can’t get it to work like they would like it. The form is a family registration form where they add general family information and then there is mini boxes where they can fill out information per member. The church wan’t certain fields to be required, now obviously if there is only 3 memebers and there are 6 available spaces, it is not going to allow them to submit it unless thoes other fields are filled out. I found out about the way you can make a subform repeat, and that could work, but I don’t exactly understand how, especially in a example I found it had the subforms going down below, and I need them to start on the left and go to the right and continue on a second page if needed. I hope you can help and if you would like to see what the form looks like so you can get a better idea of what I am talking about please let me know.
Stefan,
I thought it may not have gone through - below is my submission:
Thanks again - this site is great! Okay, in the interim, I started playing around with some advice you had given another user, along with the advice you’ve given me. In the process I noticed something wierd - Acrobat gives me the “no properties” error when I reference (just as you showed above) the variable if I am referencing off of the container that has “Flow Content” (i.e., page 2). However, if I put a subform on page 2 of the same size as the margins, put my content there, and have that subform called by the instance manager - the referencing works beautifully. I’m not sure I explained that correctly - so let me show you my code:
1. I added a field asking for how many instances I want (TextField1)
2. On that field’s exit, I put the following code:
var j = TextField1.rawValue
_summary.setInstances(j)
page2._Details.setInstances(j) // you’ll note that I’m not increasing the number of instances for page 2, but for a subform in page 2
for (var i = 0; i
Dan,
Sounds like an interesting project!
One very important thing to note about repeatable subforms is that they must be contained in a flowed container (another subform with it’s “Content” property, on the Subform tab of the Object palette, set to “flowed”). Once a subform is flowed, you can then specify the Flow Direction property to either be “Top to Bottom” (the default where new instances appear below existing ones) or “Western Text” (where new instances appear to the right of existing ones until there’s no horizontal space for new instances, at which point new instances start appearing on subsequent “lines” below existing ones).
“Western Text” flow sounds like that you’re looking for in your form. Have a look at this sample in response to a question posted on my Scripting Table Columns article. (You’ll need Designer/Acrobat 7.x to edit/run it.) The sample is using a flowed container subform (”MockTableSF”) to act as a table column container and a repeatable subform (”ColumnSF”) which acts as a column of which many instances may be added from left to right by clicking on the “Add Column” button above.
Hopefully this sample form gives you some inspiration for your form!
MK,
Unfortunately, it didn’t go through again. I think the problem is the < bracket in your “for” loop statement. Try changing the angle bracket to “<” (and other instances if they exist), then post your comment. That’ll prevent my submission form from thinking the angle bracket is the start of HTML mark-up.
Sorry about that! Hopefully it’ll work next time…
Hi Stefan,
I’m trying to create a dynamic table which will be displayed to the user when the form loads. Let me back up a bit first though. The user will select which columns s/he wants displayed on an .asp page, which will then write the names of those columns as csv string into a database field. Now, when the form loads, I’m using the js split function to put those columns into an array. Then I’m looping through the array and adding columns to the table according to what the user has selected.
The js code looks something like this:
(for now, I’m following your example on http://forms.stefcameron.com/2006/10/28/scripting-table-columns/)
var myColumns = “Col0Name,Col1Name,Col2Name,Col3Name,Col4Name”;
var arrMyColumns = myColumns.split(”,”);
for (i = 0; i < arrMyColumns.length; i++)
{
//Create a New Column
Table1.HeaderRow._Col3SF.addInstance(0);
Table1.Row1._Col3SF.addInstance(0);
}
So, up to this point, the proper amount of rows are written, but the values in the header columns are all the same. Is there a way I can reference the instance I have just added and then change the header value for that particular column? In my case, the value would be arrMyColumns[i].
Thanks a lot!
Brent
Stefan,
Thanks a lot for the info it help a whole lot. I have one more question thought, how would I add a button that would remove the last subform, like say a member accidentally clicked the button and didn’t need to.
Thanks
Brent,
Cool project! All you should have to do in order to set names into your header column fields is to capture the reference to the new instance returned from the “addInstance” method into a variable and then access the field(s) it contains.
For example, let’s say the “Col3SF” column subform contains a text field, named “ColNameTxt” which has a value set to the column name. In order to set the ColNameTxt field’s value to the pertaining column name from the arrMyColumns array, you would do the following:
Thanks a lot Stefan! It makes sense and works perfectly.
Dan,
You would simply add a new button object to the form next to the “Add Column” button and use the “removeInstance” method of the Instance Manager to remove the last instance of the “ColumnSF” subform (which can be determined by using the Instance Manager’s “count” property):
Hi Stefan,
I ran into another problem along the way. The code you gave me to build a dynamic header row worked perfectly, but when I try to add a new row I run into trouble. I can get as far as adding the actual row itself, but I can’t seem to add an instance of the cell inside the new row. So for example, the following will build both the header row and row 1 just fine:
var myColumns = “Col0Name,Col1Name,Col2Name,Col3Name,Col4Name”;
var arrMyColumns = myColumns.split(”,”);
for (i = 0; i < arrMyColumns.length; i++)
{
//Create a New Column
var oNewCol = Table1.HeaderRow._Col3SF.addInstance(0);
oNewCol.ColNameTxt.rawValue = arrMyColumns[i];
Table1.Row1._Col3SF.addInstance(0);
}
When I try to build the second row, though, it looks like one long row with no individual columns. I can build the third row with the following code:
Table1.Row1.instanceManager.addInstance(0);
or
Table1.Row1._ColSF.instanceManager.addInstance(0);
When I try to split that row up (like how the header and row are divided), I run into problems. If I try
Table1.Row1._Col3SF.addInstance(0);
I just end up adding another column to the table. So my question is, “How do start adding cells in row 2 to start making a complete row?”
Thanks a lot,
Brent
Brent,
I think the problem you’re running into is that you aren’t working with the new instance of the row that you’ve added — you’re actually still working with the first instance because whenever you’re using
it’s the same as saying
when you’re actually wanting
If I’m following you correctly, then I think you have a table, named “Table1″, which contains two rows, named “HeaderRow” and “Row1″, where “Row1″ is repeatable (via the “Repeat Row for Each Data Item” property on the Binding tab of the Object palette) and contains a single column, named “Col3SF”, which is also repeatable (via the instructions I give on my article on script table columns).
You are then able to add columns to the HeaderRow and the first instance of the Row1 row but you’re now stuck when it comes to adding columns to a new instance of the Row1 row, correct?
If so, then I think it’s a matter of getting a reference to the new instance of the row that’s returned by the addInstance method:
Give that a try and let me know how it goes.
Stefan,
You’re a genius! I’ve been struggling with this for the past few days, and I can’t believe how simple you made it. Anyway, the code works great. Thank you so much for your help.
Hi Stefan,
I am wondering if it’s possible to count the number of instances on a page so I can acess the first instance on the page and the last instance on a particuler page. What I am trying to do is…is I have a text field that is repeatable. This text field has paragraph numbers in it. I want to be able to get the first instance on the page and the last instance on the page and concatanate them together so that it tells me what paragraphs are on that particular page. For instance page 1 one can have 3 subforms with paragraph numbering of 1, 1.1, and 1.2…then when it is concatanted together says “Paragraph 1 through 1.2″ and then on the second page have 5 subforms say 1.3, 2, 3, 4, 5 “Paragraph 1.3 - 5″ etc
Thanks,
Tyler
Toylar,
Sounds interesting. What I can suggest is that you use the xfa.layout.page method to determine which instances of the subform are on specific pages. Using the xfa.layout.pageCount method, you can determine the number of pages in the entire form. If you combine the two, and make use of the subform’s Instance Manager’s count property, you might be able to achieve what you’re trying to do.
For example, it might look something like this in JavaScript (note that I have not tested this script so I cannot guarantee that it will work):
This script should be placed in the text field’s Layout:Ready event so that the “this” keyboard refers to a particular instance of the text field (assuming there’s one per page in the form, according to your description). You should be aware that the Layout:Ready event is fired every time something causes the form to need re-rendering which means it may fire very often. You might need to use a boolean variable to guard against executing it too often. Also, this script assumes that the repeating paragraph subform and text field objects are in the same scope. Otherwise, you’ll need to add the necessary SOM paths to access the paragraph subform from the scope of the text field.
Please let me know if it helps!
Interest point we just discovered with reader v 8.
We have had a script that has been working fine in reader 7 where we have a table of data in a contract that is filled in from a data input page.
Each line in the table is a subform that is added using instanceManager.addInstance() but before this is done all existing subforms (table rows) were removed in a loop using instanceManager.removeInstance(int index). This is in case changes were made on the input page they would not be just appended but updated.
This worked fine in ver 7 but we just found that in ver 8 the script failed at the first instanceManager.addInstance(). My guess is that once the last instance of the subform has been removed by instanceManager.removeInstance(int index) then the subform is no longer there to add an instances of.
The work around was to remove all but index 0 in instanceManager.removeInstance(int index) and then after all the new instances have been added using addInstance() then remove instance 0
Adobe LiveCycle Designer 8
Basically it is a list of several entries, each row with a minus-sign to remove the row and a plus-sign to insert a row AFTER the row the plus was pressed at.
The minus works fine and as long as rows are added by addInstance at the bottom the plus is also fine.
The problem starts when inserting rows somewhere in the middle. I tried this with insertInstance and addInstance+moveInstance and everytime an instance gets added, but the content of all the other rows gets cleared (and also in another flowing subform with instances to add and remove).
At time the code looks like this:
r = Allgemein.Seite1.Mitversicherte.Liste.Eintrag.instanceManager.count;
s = this.parent.index;
Allgemein.Seite1.Mitversicherte.Liste.Eintrag.instanceManager.addInstance(false);
Allgemein.Seite1.Mitversicherte.Liste.Eintrag.instanceManager.moveInstance((r-2), s);
I have no idea, why all the other fields get cleared. Do you have an idea?
Karl,
Unfortunately, I don’t think I can tell what’s going on. There’s nothing that I can see with the code you’ve provided that would be causing data in all the other instances to be cleared.
I have looked endlessly on the web and cannot find an answer to this question. I know I must be overlooking something.
I essentially have a line item subform. It is nothing too complicated. The only interesting thing is that I import the products, units, unit prices, etc. from a pre-made xml.
Well everything goes smoothly. I import the price list, add the necessary lines for each line item to be added, I total up the price correctly, I even delete erroneous line items well.
But if the users saves the form and reopens it, all instances except for the first one are gone. I’m bashing my head because it seems like this is a simple fix but I have checked every property and it all seems correct.
Please advise. By the way, best livecycle resource. I wouldn’t have gotten the form this far without this blog.
I thought maybe i could post a issue since it seems to be similar to some of the issues listed here. I’ve built a form with 4 seperate tables. Each table has 2 header rows, both are grouped together to act as one. I’m using the addInstancemanger to add rows and all that is working great. All this is on a single page and i can span onto multiple pages but for some reason if i add enough rows from any one of the tables to create a 3rd page none of the header rows appear like they do on the 2nd page. I’ve been pulling my hair out on this one for the last couple of days, it doesnt make sense to me that the header rows would paginate onto the 2nd page but not the 3rd, 4th, 5th, etc..
MJ
Adam Frey,
Thank you for the compliments. I’m glad you find my blog useful!
Normally, when you’re using straight data binding, any data that you import into the form will be saved when you save it in Acrobat (or Reader if the form has been Reader-Extended).
If you’re using script to add/remove instance of your line item subform and you’re processing the XML data manually, then this could explain what’s happening. What you need to do is either add more script to figure-out if you need to re-initialize the form to the previous state (but then I suppose this implies you stored the imported XML as data in a hidden field somewhere in the form) or you could try using the “Preserve scripting changes to form when saved > Automatically” option in the “File > Form Properties > Defaults” dialog (available at least in Designer 8.1, perhaps in 8.0).
I worked around the issue I listed above. I doubt its the “correct” fix, but it works.
I set the “initial value” of the subform to a large number (I called it 40). I tracked how many line items the user added in a hidden field. And on the initalize function for the form I used the setInstances() function to whatever the hidden field count is. It works, I’m happy, thanks.
Mark J,
I’m afraid I can’t tell what could be happening based on your explanations. I would need a little more detail about your form. For instance, is the table inside a series of flowed subforms all the way up to the root subform? Are the headers grouped together as a table section? What do you mean by “none of the header rows appear like they do on the 2nd page”?
Thanks for your reply Stefan, I’ve found so much useful information from your post’s on all your Blogs. Sorry for my vague question, I’m still learning.
The structure of the form is:
Header Layout
There is a header subform that is set to positioned and it contains several text fields.
Table Layout
I have 4 tables with 2 header rows on each and 13 columns (first header row for title of table and add row button, second row is used for column titles). The 2 table headers for each table are grouped as a table sections.
Structure:
Main page(subform-holds all page elements).table(subform-holds all tables).table1(subform-only holds table1).table1(table) — Inside each table is 1 header group for the 2 header rows and 1 table row for the data along with a remove button to remove specific instances from the table. The remove button is wrapped in a subform but it is the only table field that is wrapped in a subform on the “1 table” row.
The remaining tables all match this structure with the exception of the name changes from table1 to table2, etc.
Footer Layout
At the bottom of the form is a positioned subform that contains a static text field along with a text and date field. These items get pushed down as more rows are added to the tables.
It was by chance that i even noticed this issue but my form is pretty much packed on a single landscape page and as soon as i add a single row to any table a new page is created which is all great but lets say i just kept hitting the add button on table 1 and it keeps adding rows as it should. The table 1 header rows are repeated onto the second page as expected but if i continue to hit the add button and a 3rd page is created, none of the header rows get created on the 3rd page for table1. I can only see them for the first 2 pages of the form. Now if i stop adding rows to table1 and start adding rows to table2 it will do the same thing and duplicate the header group for the next 2 pages then it stops duplicating the header row onto each page after 2 more pages are created.
I can only guess that there is a setting that I’m missing, that indicates the number of times a table header row can be repeated or in my case a header group.
thanks for you reply and help on this,
Mark J
Mark J,
Sorry for the delay. We’ve been heads-down lately working on some code.
You’ve provided a very good explanation of your form and I was able to replicate the issue you’re having. It looks like you’ve uncovered a bug where if the object being used as an overflow leader (which is what the table “header” section becomes with respect to the table when you choose to have the section repeat on subsequent pages) has flowed content (in this case, two header rows are flowed within the table section), the rows end-up positioned on top of one another on subsequent pages. It’s strange that it only happens after the second page for tables but I think the underlying issue is the same.
My only suggestion at this point is that you replace the section and two header rows with a single row, make all cells span the 13 columns, make the cell into a single subform with positioned content, make that row the height of two rows and insert the necessary form objects to get your table title, column titles and button into it. Then mark that single row as a header row and see if it will repeat correctly on all pages.
As for the bug, I will definitely report it so that it gets fixed in a future release. Thanks!
Mark J,
I inquired about this table header bug and it seems there’s no bug after all: You should make sure that your section is set to repeat on subsequent pages (via the “Object palette > Pagination tag”) as well as making sure that it’s repeatable (by checking the “repeat for each data item” option on the “Object palette > Binding tab”). Doing this fixed the issue in my form.
As for the issue with overflow leaders having flowed content, that’s apparently not yet supported. Only overflow leaders with positioned content are fully supported at this time.
Give it a try and let me know.
I don’t know where to write about my problem, so I will try here. I have a repeating subform, with dynamic captions, for both romanian and english language. The problem is, that when the second instance of the subform is generated, the captions are not loaded from the XML file that has them, but they present the text that was entered in designer when the form was first drawn. Can you help me? Thank you!
Hello,
How is the second instance of the subform being generated? Are you using a button’s click event and executing the “addInstance” method of the subform’s Instance Manager? If that’s the case, are you calling “addInstance(1)”? The “1″ as the parameter will cause new instances to be merged with any data that has yet to be merged into the form. If you’re calling “addInstance(0)”, any remaining data will not be merged into the new instance.
You mentioned you were using dynamic captions. I assume you’re doing this with Designer’s Dynamic Property feature. Consider the following data:
If you had a repeatable subform with a text field inside of it and you wanted the text field’s caption to be “cap 1″ for the first subform instance, “cap 2″ for the second instance and “cap 3″ for the third instance, you would define the subform’s binding as “instance[*]” and the text field caption’s dynamic property binding simply as “caption”.
Stefan,
Your blog is a great resource and has helped me tremendously to create a working dynamic form. Could you please help with a problem I have with a repeating subform using instance manager.
I have a form with two master pages (’portrait’ and ‘landscape’). the majority of the form is laid out as ‘portrait’. On these pages the instance manager works just great to repeat subforms.
I have one dynamic subform on the ‘landscape’ master page. After this subform, the remainder of the form is set up on ‘portrait’ master pages.
So, here’s the problem: when I use the instance manager and repeat the ‘landscape’ subform (which then overflows to another page), the subform is generated on a ‘portrait’ page, instead of a ‘landscape’ page.
In the pagination for this repeating ‘landscape’ subform, I have the “Overflow” set to “Go to Page’landscape’” . However, when I test the form, it still generates the subform onto a ‘portrait’ page. I have tried many combinations of pagination settings and none have produced the desired outcome: the subform repeated onto a ‘landscape’ master page.
I am new to livecycle. Is there something here I am overlooking? Any help would be greatly appreciated
Troy Seiler,
Normally, flowed content such as repeatable (dynamic) subforms is placed on body pages, not master pages. I don’t think master page content flows quite the same way. You should be able to move those subforms onto the body pages and use the “Object palette > Pagination tab” to ensure that they get placed on the correct master pages (”landscape” vs “portrait”) and then use the “Overflow” property as you’ve set it. That should get the subform placed on the “landscape” master page to overflow correctly onto another instance of the “landscape” master page.
About master pages vs body pages: Note that body pages contain the content that flows from one master page to another. A master page defines various properties about the pages onto which body content flows. Master pages can have one or more content areas which define where body content (on the body pages or “Design View” since Designer 8.0) flows. A new instance of a master page is created every time all the content areas on the current master page instance have been “filled” with body content from the body pages. You can dictate what master page is used for the next “physical” page (needed by the remaining flowed body content) by using the “Object palette > Pagination tab” (available for subform-based objects).
Stefan,
Thank you for responding so quickly. I don’t think I expressed my problem clearly. I have the pages configured as you suggest (on body pages, with master pages assigned using the pagination tab). It seems the problem lies with switching between ‘portrait’ and ‘landscape’ then switching back to ‘portrait’. The form works well when I place the ‘landscape’ body page at the end of the form (so it’s the last page). However, when the ‘landscape’ body page is sandwiched between two ‘portrait’ pages, a ‘portrait’ body page is generated for overflow, regardless of the configuration on the pagination tab.
Here’s the simplified hierarchy of my form (this arrangement always generates a ‘portrait’ page, despite the pagination overflow being set to ‘landscape’):
-Master pages
-portrait
-landscape
-subform1(flowed)
-Body page1 (pagination=portrait)
-subform2(flowed)(repeated)
-Body page2 (pagination=landscape;overflow=landscape)
-subform3(flowed)
-body page3(pagination=portrait)
However, when I rearrange the hierarchy as follows, the form works properly (i.e. a landscape page is generated for overflow):
-Master pages
-portrait
-landscape
-subform1(flowed)
-Body page1 (pagination=portrait)
-subform3(flowed)
-body page3(pagination=portrait)
-subform2(flowed)(repeated)
-Body page2 (pagination=landscape;overflow=landscape)
I have found another post on a forum suggesting that this is a bug. However, I cannot find confirmation (or a fix) if this is the case.
the hierarchy spacing was not preserved in my last post. To clarify, the body pages are below their respective subforms in the hierarchy, and ‘portrait’ and ‘landscape’ represent the two master pages
Stefan, you may be my last hope. Livecycle is new to me and I’ve been learning a lot in a short amount of time. I’ve exhausted my search online for help and I have come to you as a last resort. What I want to do seems so easy, but I’m having trouble repeating row data from one row to the next.
I have a repeatable form that a user will fill out. I am able to add/delete a new row w/o a problem. Some of the fields in the rows will stay the same. I am trying to creat an instance of a new row, capture the data from one field (lglIdentity[0]) and paste it in the next (lglIdentity[1]) and so on and so on. here is my code:
details being my table name, detail being my row name and lglIdentity being the cell to copy and past to the next row.
var lglIdentity
lglIdentity = details.resolveNode(”detail”).lglIdentity.rawValue;
xfa.host.messageBox(”legal is: ” + lglIdentity, “Debugging”, 3) //this captures the object just fine
var inst = details._detail.addInstance(1);
var lglIdentity1
lglIdentity1 = details.resolveNode(”detail[1]“).lglIdentity[1].rawValue;
inst.lglIdentity1.value = lglIdentity
This is only half the problem though. Eventually I will need to copy this data to multiple rows, depending on the number of rows. I’m assuming I’ll need some kind of loop, is that correct. How do I go about this all? I’m at a dead end right now.
Is there something here I am overlooking? Any help would be greatly appreciated, thank you.
Hello,
I have a subform that includes an image field (the one you click to load your own). Let’s assume there are two instances of the subform with different images in each. When I insert an instance between the two the image in number 2 (now 3) disappears. If I remove instance 2, instance three (the original 2) comes back with the image loaded. If I add an instance at the bottom everything stays copacetic. It is only when inserting between rows that the images disappears. How can I get the loaded image to travel with the moving instance?
Thank you
troy seiler,
I understand what you’re seeing looks like a bug but I can’t exactly pin-point whether it is or not. I am wondering, however, why you’ve structured your form as you have. Why did you put page subforms inside other subforms, as in
I would try removing those body pages and just using the subform1, subform2 and subform3 subforms (which I believe are parented to the root subform given the hierarchy you listed). You can make subform2 repeatable just like you could “body page 2″. Then set your pagination on the subforms and see if that fixes the issue. I have a feeling that the layout engine is getting confused on which master page should be used for the following subform (i.e. it finishes rendering “body page 2″ with the landscape master page and then renders subform3 — which likely uses “following previous” as its pagination — and puts it onto the landscape master page even though the subform inside subform3 says that it should go on the portrait master page).
Evan Buxton,
It looks like you’ve discovered a bug. Thanks for pointing this out. Fortunately, there’s a workaround in the meantime: After inserting the subform instance, force the form to be re-rendered using xfa.layout.relayout():
What’s happened is that the image has, in fact, followed along with the instance of the subform however Acrobat/Reader hasn’t properly updated the form’s layout after inserting the instance in the middle. I’ll make sure this is reported appropriately.
Stefan,
I see your point. I believe I tried what you are suggesting, with the same results. But, I will play around with the hierarchy as you suggest and see if I can get this to work. Thanks for your input.
Just to explain. . . and I apologize for making you pull the complete story out of me piece by piece. . .
The reason I have the subform within a subform hierarchy is that I have designed the form with the ability to repeat a group of several pages AND to individually repeat a single page within the larger group. It is a very large form, and basically, I found it slightly easier to work with using the current hierarchy.
-Troy
Stefan,
I’m trying to create a form calculation that returns 20% of the sum of some other fields but has bounds on both ends at 200 and 450. Here is the code that i have thus far…
if ((this.getField(”Provident_YSP”).value + this.getField(”Check_Total”).value - this.getField(”Appraisal”).value) * .2 > 450 )
this.getField(”Superior_Lending_File_Fee”).value = “450″;
else if ( (this.getField(”Provident_YSP”).value + this.getField(”Check_Total”).value - this.getField(”Appraisal”).value) * .2 < 200 )
this.getField(”Superior_Lending_File_Fee”).value = “200″;
else
this.getField(”Superior_Lending_File_Fee”).value = (this.getField(”Provident_YSP”).value + this.getField(”Check_Total”).value - this.getField(”Appraisal”).value) * .2;
The problem i am running into is that it doesn’t work after i close and reopen the form. It does show the minimum 200 value, but doesn’t update when the preceding fields are changed. Could you help me out with this?
-Jeff
Jeff Maughan,
First, the calculation should be inside a Calculate event on the field that needs to show this percentage value.
Second, you’ve scripted your calculation in such a way that you’re circumventing XFA in order to get field value. I believe this is bypassing the Calculation Engine which means it won’t be able to establish dependencies on this field to other fields such that when their values change, this calculation is run again.
Try it like this (where you access field values from within XFA):
where the pattern of
becomes
Brad Gubanich,
I just found your comment from last June still awaiting moderation. The email notification must’ve been flagged as spam and got deleted.
In case you’re still wondering how to do this, based on the code you quoted:
you would simply execute this script when adding a new instance of the “detail” row (assuming I understood what you’re trying to do):
The above code will determine if there’s more than 1 instance after adding one. If there are at least 2 instances, there’s a preceding one from which the value of lglIdentity can be retrieved. The code proceeds to get that value by crafting an expression like “details[x]” which it gives to the “resolveNode” method of the “details” table object (where “x” is the instance number of the preceding instance). From there. it gets its lglIdentity field value and assigns it to the new instance.
Stephan,
Thanks for the great blog i have found many useful solution to issues and found it to be a great resource for my education in form design.
I’ve be challenged with something that i though would be an easy solution but cant for the life of my figure this one out. My employer has asked me to create a radio button set at the top of a form that repeats on to each page but each repeat must retain the value of first radio button set. I put the radio button set on the master page and repeats as expected but doesn’t retain any of the values from the first set on the new page. I’m thinking i should have put the radio button set in a subform and used the instancemanger to copy the previous set while maintaining the same values if that is possible. I would appreciate any incite into this that you could offer a rookie. :)
thanks,
Mark
I figured it out. So simple i feel stupid but setting the radio button set to Global on the Binding tab gave me this intentionality.
thanks,
Mark
Hi Stephan - I’ve found your blog very helpful. Thank you! You seem to be very willing to help, so I’m gonna ask … I can’t get my dynamic form and instancemanager to work.
Here is what my form looks like:
PurchaseAuthorizationForm
>(Master Pages)
>page1 (flowed subform)
>>PrintButton
>>Title (positioned subform)
>>AuthorizationAgreement (flowed subform)
>>>items (flowed subform)
>>>>item (positioned subform, on Binding tab the ‘Repeat Subform’ is checked)
>>>>>2 text fields (that I want to repeat)
>>>>addAnotherItem (flowed subform)
>>>>>btnAdd (the button that runs: xfa.PurchaseAuthorizationForm.page1.AuthorizationAgreement.items.item.instanceManager.addInstance(true);)
rest of the form is incomplete
What I want to happen: when user clicks the btnAdd, the item subform and it’s two text fields are repeated.
What am I missing?!?!?!?! This is driving me crazy. I’m using the Allegiance multiBeneficiary sample as an example with no luck.
THANKS!
Laura,
You’re welcome!
Are you running this script in JavaScript or FormCalc? Are you seeing any error messages? If you’re using FormCalc, you should get a message box with an error. Otherwise, you’ll have to look in the JavaScript Console in Acrobat to see if there are errors (when previewing your form in Designer, click on the form and then press “Ctrl + J” to show the console).
Stefan,
Great to see your site, you are really helpful!
I have a growing table, user can press Add button to add rows while each row can have different height (the cells allow multiple line) just depends on what they input.
What I wanna get is the whole table’s height, (I cannot get the height for flowed subform). So instead I decide to add up all the rows’ height for that.
Although I can get the total row counts for it:
var oRow1 = xfa.resolveNode(”Subform1.Table1.Row1″);
rowcount = oRow1.instanceManager.count;
I have problems referencing each instance row’s cell
(suppose the body row consists of a Name and Address field):
I think somehow the code should look like:
oRow1.Name[0].h (for row 1)
Thanks a lot.
Hilary,
What you actually need to do is get the layout height of the table after the user has entered their text. It’s only once the form has been re-rendered that you can get the true height.
Since your table’s height varies, if you were to get the height of the table, it might say “5in” when it’s actually 11.483 inches tall after all the text has been entered into all of the rows. Same goes for an individual row: It’s height might be “3in” but it’s set to grow in height to accommodate multiple lines of text in the fields it contains. The actual row height might be 5 inches for a particular row.
The way you get the rendered height of the table or a row is by using the xfa.layout.h() function which takes a reference to the object whose height you want to retrieve.
To get the height of the table, you would call
The second parameter represents the units in which the height should be returned. You can specify “in”, “pt”, “cm” and “mm”.
To get the height of each row, you would do this:
Note, however, that you can’t use the xfa.layout.h() function until the form has been rendered which means you would typically use it in a Click event initiated by the user or you would use it in the LayoutReady event which is fired after the form has been rendered.
Stefan,
Thanks for your reply, I can finally handle it.
Yet there is another problem I encounter now.
My form is a dynamic one with data flowing. After filling the form, it has to be rendered such that a new layout comes out for printing.
It is ok if I separate these actions:
0) Originally the first original page is displayed for filling data. Data may span on next page. While pages used for rendering a new layout will be hidden at the beginning.
1) There is a Preview button on the first of original page(s), and on click, scripts will run to hide the original page(s) while the new rendered page(s) become visible.
2) On the rendered pages (read only), there is a Print button for printing which simply codes:
xfa.host.print(1, “0″, (xfa.host.numPages -1).toString(), 0, 0, 0, 0, 0);
3) There is also a Preview Close button so that on click, the fields of the rendered pages will be cleared and hidden, while the original pages will reappear again.
However when I intend to use a Print button to combine all above steps (Print Preview -> Print -> Close Preview) in one script, when the print dialog comes out, it just display a blank page for printing.
It seems that xfa.host.print occurs not on the right time.
Any idea?
Hi Stefan,
Just a bit of amendment on my post above, actually if I press the Print button, when the print dialog comes out, it only displays one page which is the 1st page of all rendered pages, so if there are totally 3 pages, it will miss out the two pages then.
On debugging, I check out that xfa.host.numPages = 1 instead of should be 3.
and when I intend to force printing all 3 pages using:
xfa.host.print(1, “0″, “2″, 0, 0, 0, 0, 0); it becomes worse that it doesn’t prompt out a print dialog and seems stop running code.
Hilary,
It could be a delay in the rendering of the pages for print as a result of your “print preview” script. You could try forcing a re-layout of the form just before you issue the xfa.host.print call:
The relayout() call should be blocking and should take place immediately which means that by the time your script executes the print() call, the pages should be rendered.
If that doesn’t work, try having your button no do the “close preview” step to see if you can print what you want. If that works, then it’s the xfa.host.print command that is asynchronous and executes only after the script has finished executing, at which point your “close preview” step has removed all of the pages meant to be printed…
Hi Stefan,
Thanks for your prompt rely but I had tried relayout() already that it doesn’t work. Taking out the “Close Preview” step can avoid the blank pages but only first page of the rendered pages got printed. It seems that xfa.host.numPages still equal 1 after relayout().
Any other method that I can perform these steps in just one button?
Preview (rendering) => Print => Close Preview