Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

Calculate Scripts

I just learned something very interesting while answering a forum thread just now which I thought I should share with the rest of you.

In all the scripts I’ve written so far, I had never realized this simple rule: When writing calculation scripts to set the value of certain fields, the line in your script which assigns a value to the field on which the Calculate event was fired should always be the last line in your script. This is because the last-executed line in your script is the one that the XFA Object Model will use to determine the value of that field.

While it’s generally not recommended to do much more than set a field’s value in the Calculate event, reality is that most of us use it for much more than that: Since it fires on all fields on a form after a field’s value changes, we may use it to affect the presence, color, dimension, etc., of some fields which depend on the values of other fields. Therefore, it’s very easy to fall into this trap where your calculation script isn’t working probably simply because you haven’t structured it correctly.

Take the following FormCalc script as an example:

if (NumericField1 > 0) then
	NumericField1 * 10;
	$.presence = "visible";
else
	0;
	$.presence = "invisible";
endif

This scripts runs in the Calculate event of a numeric field and, if NumericField1’s value is greater than zero (0), results in the field becoming visible and its value set to the product of NumericField1’s value multiplied by 10. If NumericField1’s value is zero (0) or less, its value is set to zero (0) and it becomes invisible. Note the order of the lines which set the field’s value and the ones which set its presence: The value is set before the presence is set.

The result of this script is that the presence is affected properly depending on the value of NumericField1 however, since the last-executed line is “$.presence = ‘visible’” (or “invisible”), the value acutally assigned to the field is “visible” (or “invisible”) which evaluates to “0” as a numerical value. Therefore, with this script, the value of the product field would always be zero (0).

If you change the order of the lines which set the field’s value and presence as follows:

if (NumericField1 > 0) then
	$.presence = "visible";
	NumericField1 * 10;
else
	$.presence = "invisible";
	0;
endif

Then both the field’s presence and value will be set correctly because the last-executed lines in each block are the ones which set the field’s calculated value.


Posted by Stefan Cameron on May 15th, 2006
Filed under Events,Scripting
Both comments and pings are currently closed.

42 Responses to “Calculate Scripts”

  1. Rob McDougall on May 17th, 2006

    Hi Stefan,

    You’ve touched on a good point here. I think there are a couple of other things about calculate scripts that are important to mention as well:

    You state that “it fires on all fields on a form after a field’s value changes”. This statement is perhaps a bit misleading. I’m sure you know that the calculate event doesn’t fire on all fields after a field’s value changes, but it does fire on all dependent fields. This is an important distinction. There’s a dependency engine built into the engine that fires the calculation events. This means that the calculate event only fires on fields that need to be recalculated and the calculate event does not fire on fields that could not possibly have changed. This saves processing time and speeds up the form. It can also be leveraged to improve a form’s performance by breaking down a large calculation which fires often because it has many dependencies into smaller calculations some of which fire less often because of this shortcutting mechanism.

    A consequence of this “dependency shortcutting” is that you cannot determine the number of times a calculate script will fire during the course of filling out the forms. Since a calculate script may fire once or it may fire a hundred times, you have to be careful about what you do in a calculate script. I always tell new Designer users to make their calculations “stateless”… that is, don’t create scripts that depend on persisting some “state” between each firing. A classic example of this is incrementing a counter inside a calculation script. Because a calculation may fire many times during the forms-fill process, there’s no way to determine what the final value of statement like “field1 = field1 + 1” will end up being. In this case, “field1” is state that persists between script invocations. It is used as both input and output. Scripts that have separate and distinct inputs and outputs do not maintain any state between invocations and are therefore safe.

    Another common mistake is to put some user interaction, like a msgbox, into a calculation. Doing so often produces annoying results as the calculation fires and re-fires.

    There’s plenty nooks and crannies hiding in the shadows of the Designer scripting engine. I look forward to you shedding further light on them in upcoming blogs. Keep up the good work!

    Regards,
    Rob McDougall
    4Point Solutions

  2. smvo on October 11th, 2006

    Stefan,

    I would like to post a problem/question, not very related with this tutorial, however I didn´t find a tutorial answering this quesion on your site.

    So, first of all, sorry for this post.

    The problem is this:

    I have a text field and behind it a tiny subform object.

    When the user click to print the document, I want to see if the text field as any value:

    If it has any value, the text field should print. However, I would like to see no borders on the printed field… just the value on it.

    If the text field has no value, I would like to print the subform.

    I think I need to make a combination of the properties: relevant and presence, however, I couldn´t realize how to do it, yet.

    Note that I wouldn´t like to change events specific to the objects (text fields and subform behind it), because I could have a lot of them. I rather have a cycle in a button to test all the fields.

    Note also that I wouldn´t like (not me.. the users..of course) to see object appear and disapear as the user clicks the print button, so change visibility in the pre print and post print is not the best solution… if relevant property works it would be nice, I think. In other words, I would like to control the printing of the object without changing is presence/visibility on the form.

    Any ideias?

    Thank you for your help.

    Sérgio

  3. Stefan Cameron on October 16th, 2006

    Sergio,

    It took a little to research this and get the low-down on the //field@relevant attribute.

    Unfortunately, it’s not something you can script (i.e. change on-the-fly at runtime in Acrobat) and what’s more, it’s only supported on button fields at the moment (even though it’s a valid attribute on the field XFA element which basically defines any field type). While support for the “relevant” attribute was fully supported by XFA as of Designer 7.0, Acrobat 7.x only supports the “relevant” attribute on buttons — and this only at load time (hence the inability to script against it).

    In light of this, I’m afraid I can only suggest that you use the prePrint and postPrint events on the print button to check the fields that should or shouldn’t print and use the //field@presence attribute to control which ones do and which ones don’t.

    Fortunately, significant improvements have been made with respect to Acrobat’s support of the //field@relevant attribute in the up-coming release of Acrobat 8.

  4. Sérgio on October 18th, 2006

    Stefan,

    Is that version 8? Or version 8 is only for acrobat professional?

    Do you know what is the expected date for this release?

    One more thing:

    Is there an easy way for get and cycle along the fields in a subform?

    Thank you.

  5. Stefan Cameron on October 18th, 2006

    Sergio,

    Acrobat Professional usually comes with a version of Designer in towe. Unfortunately, that’s about all I can say at the moment.

    As far as finding all the fields in a subform, you can try a loop like this:

    for (var i = 0; i < oSubform.nodes.length; i++)
    {
      var oChildNode = oSubform.item(i);

      if (oChildNode.className == “field”)
      {
        // do something with the field
      }
    }

  6. Sérgio on October 20th, 2006

    If the subform has an array of fields, shoudn´t I be able to get the index od each one using instance manager? I tried it on the loop you gave me, but it returns always the same instance number 🙁

    Thank you!

  7. Stefan Cameron on October 24th, 2006

    Sergio,

    The Instance Manager is strictly for use on repeatable/dynamic subforms. It won’t help you find the fields contained within a subform. For that, you need to use a loop similar to the one I suggested earlier.

    Have a look at my post on processing all the fields within a container. It should give you a more complete example of what I tried to illustrate with my little code snippet earlier.

  8. Sandy on November 2nd, 2006

    I am creating a form for people to sign up for an event for our boy scouts group. I am using Designer that came with my Adobe Professional 7. I want to create value fields that add themselves to a total. For example… the registration is $15.00 and they have the option to order a boy scout knife souvenir at $8.00 per knife. How do I get the quantity field to populate the knife $ total field and then add it to the grand total field? Thanks for the help!

  9. Stefan Cameron on November 3rd, 2006

    Sandy,

    That sounds like an interesting project! I believe this would be simply solved by creating some simple calculation scripts.

    First, I would use a numeric field for the quantity of knifes to be purchased. Let’s call this field “Quantity”.

    I would then use a second numeric field named “KnifeCost” which would hold the subtotal for the cost of the knifes. Since this field will simply display the subtotal for the knifes and isn’t meant for user input, I would make this field “Calculated – Read Only” using the Type property on the Value tab of the Object palette.

    Next, I would use yet another numeric field. Since this one would be used to calculate the grand total (which isn’t meant to be modified by the user), I would name it “Total” and set as “Calculated – Read Only” as well.

    After setting-up the fields, all that’s left to do is tie them together using some very simply scripts:

    On the KnifeCost field, you need to show the result of the quantity of knifes orders multiplied by the unit cost per knife. Using the Script Editor palette, select the KnifeCost field, then select the Calculate event and set the following FormCalc script:

    Quantity * 8

    Now, whenever the value of the Quantity field changes (e.g. the user enters “2” for 2 knifes), the value of the KnifeCost field will automatically change to “16”, the product of 2 * 8.

    The last thing you need to do is wire-up the Total field such that it calculates the sum of the cost of the knifes and the $15 for the membership:

    15 + KnifeCost

    That should give you a form with 3 fields where the user only enters a quantity of knifes to order and the cost for the knifes and the total cost for the order, including the membership feeds, is automatically calculated and displayed in their respective fields.

  10. Sandy on November 8th, 2006

    Thank you so much! It worked! I appreciate it. I am having the form submit to my email (or they can print and mail) and will then have it populate an excel spreadsheet. This way I can manage the data without having to type it in! I plan to use the method that is detailed with the xml file that is received:
    To create a spreadsheet from one or more form data files you have received:

    1. Save the data files to a place on your computer, giving each file a
      unique name and making sure not to delete the ‘.xml’ file extension.
    2. In Acrobat, choose File > Form Data > Create Spreadsheet from Data Files.
    3. Click the ‘Add Files’ button to chose the data files.
    4. After the data files are added, click the ‘Create Spreadsheet’ button
      to create a Spreadsheet that contains data from selected data files.

    I have never used this method, but it seems straight forward. Any tips or links to managing this data?

    Sandy

  11. Stefan Cameron on November 8th, 2006

    Sandy,

    That’s wonderful! I’m glad it worked.

    Acrobat’s recommended way to bring the XML data submitted via email into an Excel spreadsheet sounds like the easiest way to go. It should be simple to do and if it’s good enough for your needs, then I wouldn’t look much further.

    Since you’re receiving XML data files, you need to do something with them in order to combine them into something meaningful like a spreadsheet. Otherwise, you’re using a database or a web service and the data is going straight into a back-end data store of some kind and you can just run a report from that storage system (e.g. an SQL query).

    Let me know if you have any problems with it and I’ll see if I can get some answers.

  12. Sérgio on November 9th, 2006

    Stefan,

    In what regards to the //field@relevant attribute and Acrobat 8, I can see that there is a visible screen only and visible print only options in the designer. this seems exactly what I need.

    However, it seems I can´t change it dynamically to a subform on a click of a button. Does this means that even in Acrobat 8 this property is only supported at load time?

    Thank you!

  13. Sérgio on November 10th, 2006

    Stefan,

    Just to be more explicit: In fact I can change the visibility of a text field in the screen. The fact is that this is not the real problem.

    The problem is this:

    I have a text field with borders. When the field is empty, I want to print a subform behind the field and not print the field itself.

    When The field as a value, I want to print the field without the borders.

    We had already talked about this support in version 7. Version 8 give us more options, specially in what respects to the support of the relevance property in more fields like text fields.

    So, to solve my problem I make this (version 8):

    1 – insert a text field/numeric field on a form. Set is presence to visible.

    2 – On a button event click I test if the field as any value: if it does, I make the relevant=”+print”; if it doesn´t I set the relevant = “-print” The goal is to have the field always visible at the screen but to print it only when it has any value.

    However, I realised that when the field has a value, the relevant =”+print” will make the borders/field hide on the screen (but the data is visible) and only the field (with the borders) will print without the data… This seems a bug to me.

    This is really strange, because setting the relevant property should only affect the presence of the field in the printing and not in the screen. Even if this was not true, setting the relevant property to +print should never change the visibility of the field… because +print is to be visible.

    Well, because that It seems that even in version 8 I will need to use prePrint and postPrint events…

    One problem in this solution is that it would be better to make a iteration for all fields one time than many iterations by each field. This is because, for each field, I need to test if there is a subform behind it (of two possible kind), and if so, hide or not the subform or the field, depending if the field as any value or not.

    To avoid this interactions, I wonder if it is possible to get to a subform object directly by using the location of the field.

    For instance, if I have the field “name” I know there will be 3 possibilities; don´t have a subform behind it; have a subform behind it with this rule (a prefix_nameofthefield): “P_name_of_the_field”; or have a subform behind it with this name “I_name_of_the_field”.

    So, for each field, I know the name of the subform related to it (if it exists) and that it is located in the same container of the field.

    I could make something like this to get to the subform: field.parent.resolveNodes(…). However I think this will make a iteration by all the objects in the field container that, for almost the cases, will be the subform page! Because the code will run in the print event of each field it doesn´t seems the better solution. What I would like was to get the location of the field like “page.subform.subform.fieldname” and change it to “page.subform.subform.P_filedname” and to “page.subform.subform.I_filedname”. In other words, I would like to admit that these subforms exists at first, then I will ignore any error if it not exist (one or both). For the one that exists, I will like to make it visible or not when printing (they should never be seen on the screen).

    Do you think this could be a better solution?

    Thank you

  14. Stefan Cameron on November 11th, 2006

    Sergio,

    Thanks for the valuable feedback on the use of the relevant attribute.

    Before I go any further, I just wanted to make sure that you’re testing this with Acrobat 8 and saving your form as an “Acrobat 8 Dynamic XML Form”. These two conditions have to be met in order for the relevant attribute to be supported on objects other than buttons.

    I would also like to clarify the use of the relevant attribute: It’s used to specify the views in which the field is relevant. Currently, there are only two views supported in Acrobat 8: screen and print. Also, the relevant attribute works in conjunction with the presence attribute — it isn’t a replacement for it. That being said,

    • if a field has presence=”visible” and relevant=””, it is visible in both views (screen and print);
    • if it has presence=”visible” and relevant=”+print”, it is only visible in the print view; and
    • if it’s visible but has relevant=”-print”, it is only visible in the screen view.

    If the field is made invisible or hidden (using presence=”invisible” or presence=”hidden”), the relevant attribute is completely ignored.

    Therefore, the behaviour I would expect is that setting relevant=”+print” on the text field at runtime would cause the field to be hidden from the screen view immediately but still print. Unfortunately, there’s a bug with that where the field remains visible. You can get around it by forcing the layout to be updated immediately after setting the relevant attribute by calling

    xfa.layout.relayout();

    I’ve also just reported the bug to the Acrobat team.

    As for your question about using the resolveNodes() method, yes, you’re correct, it could be an expensive call as this version will search for any match to the specified SOM expression and will return a list.

    You should use the singular version, resolveNode(), which returns a single node or a null reference if no match is found. This is really the only way to determine the existence of a field based on a generated name.

  15. Sérgio on November 17th, 2006

    Hello Stefan,

    First of all, thank you again for your help.

    In what concerns to the printing of the borders of a field, I would like to give an opinion about a functionality LiveCycle designer could give us: a property that would allow to indicate a border not to print, for instance, a PrintBorders (true/false) property. The FormFlow99 designer had it when XFA was from Accelio. This property should be able to configure using the IDE and not only programmatically.

    I think this is important because as the PDF format becomes more used inside the organizations, it is important to give to the PDF a user screen view and a customer paper view. We cant think about a PDF as only a way to put data onto a document, but also that it will be given to our customers, and so they don´t want and don´t need to see the PDF like the users do.

    Another way to achieve this would be to make the relevant property of the borders functional.

    In what respects to the
    xfa.layout.relayout();
    method, what are the implications?
    For instance, If I have a lot of code distributed by many events of the form and of the objects in it, will not some of them be activated “n” times? I´m a little afraid of doing something force because one specific functionality and then put all the others functionalities in danger…

    Finally, in what respects to “determine the existence of a field “, I first need to get the position/location of the input field in the form. If I have a variable that is a field object, is there any property/method of the field (or another object) that give us the path/location/position of it inside the PDF? (ex.: form.subform1.subform2.fieldname). I need this position to change it and find the other object behind the first one using resolve node.

    Just one more thing: can I send you a working example of what I´m trying to achieve. I would like to have sure I´m not using to much steps on this, because almost all the filed in the forms will use this kind of script. By the way, this kind of example could be useful to your site as I believe many people needs to print PDF like this.

    Thank you.

  16. Stefan Cameron on November 19th, 2006

    Sergio,

    Have you tried using

    this.border.presence = “true|false”; // show/hide field border

    this.ui.oneOfChild.border.presence = “true|false”; // show/hide value border

    in order to show or hide borders? I know it’s not quite as nice as a “this.showBorders” or even setting the border’s relevant attribute but it would get you to where you need to go for now.

    We’ve recently been looking at our scripting methods and properties to see if there are some that are missing. This is a great suggestion which I’ll add to our list of suggestions.

    As far as “xfa.layout.relayout” is concerned, this method just causes the entire form to be re-rendered. It shouldn’t cause any calculations to fire, for example, but it will cause “Layout:Ready” events on all objects to fire but this happens under normal layout circumstances anyway. Therefore, the danger could lie in the Layout:Ready event if you’re using that one to do some extensive scripting. Otherwise, performance should be in direct relation to the number of pages in your form and the number of objects on each page.

    Finally, you’ll want to use the “somExpression” property on an object in order to get it’s “address” in the Scripting Object Model (SOM). For example, if you’re in the context of the “fieldname” object you gave as an example, doing

    this.somExpression

    would return something like

    form1.subform1.subform2.fieldname

    Note that the shortest unique SOM expression for the object will be returned so it may simply be

    form1.fieldname

    depending on other field names within the form.

  17. Sérgio on November 20th, 2006

    Stefan,

    I realize there is a “comb of” property new to Acrobat 8. that comb is what I´m trying to achieve (with hidden subform), and so, maybe I could try to used it.

    However, When printing with values on the field, I would like not to print the comb but only the value. Is this possible?

    Thank you

  18. Sérgio on November 20th, 2006

    Stefan,

    Another thing…

    Shouldn’t this.border.presence = “hidden” make the border of date-time fields and dropdown fields hidden?

    I´m trying to put these borders invisible when printing (to print just the data, but it seems not to work.

    thank you again..

  19. Stefan Cameron on November 21st, 2006

    Sergio,

    Remember that

    this.border

    represents the field’s nominal extent border. That is, the border surrounding the entire field.

    If you’re wanting to hide only the content area border (the border around the value portion of the field), then you need to set the visibility of the

    this.ui.oneOfChild.border

    property.

    Incidentally, the appearance of a field’s comb is controlled by the third edge of the content area border property. Therefore, if you make that border’s presence “hidden”, you’ll end-up hidding the comb completely.

  20. Sérgio on November 22nd, 2006

    Stefan,

    Thank you for remember me the difference between this.border and this.ui.oneOfChild.border

    In fact, that was the reason why I couldn’t take of the border of a field’s comb object.

    This is very good because I can now simulate comb/divisions in an object without using hidden objects.

    The only problem I have is with date object and multiline objects.

    Date object can be combed of, despite the display pattern can create some problems. So, I think I will be able to use them with some modifications.

    Multiline objects can´t be combed. If we combed it, the object will not be multilined.

    In what respect to these multiline objects, what I would like to get while printing was not, in fact, a great number of squares by each line (despite it would be a possible “must to” feature to someone), but a line (underline) by each possible line (defined by the fixed sized of the field). Thus, if the user didn’t input any value on that field, the printing document would have a predefined number of lines where the client or the user could write on.

    So, my question is, at the printing time, do you think it would be possible to programmatically set an underlined value to this kind of objects? Of course I could set the value of the field to: “___________”, however, how can I now how much of this character “_” I would need to assign? I must guarantee that all the capacity of the field is used to have the same dimension in each line.

    This may seems a stupid question, but it can take of from my forms about 20/30% of its weight and an important improvement on its performance.

    Thank you.

  21. Stefan Cameron on November 24th, 2006

    Sergio,

    I see your point. That would be a nice feature for print and I’ll make sure we take note of it.

    Unfortunately, I don’t think there’s a way to achieve that you’re wanting to do.

    The difference between a field which has a comb and one that doesn’t is the mere presence of the <comb> node as a child of its field.ui.oneOfChild node (“oneOfChild” being, for example, “#textEdit” or “#numericEdit”).

    Since nodes can’t be added or removed to the template DOM at runtime (e.g. in Acrobat), there’s no way I know of to remove the comb element from a field in order to make it a “regular” non-combed field.

    If that were the case, you could’ve made it regular and set an underline border on the value area (field.ui.oneOfChild.border…) using the PrePrint event and the reset the comb on the PostPrint event.

    I’m afraid the best thing I can suggest in this case is to set the

    field.ui.oneOfChild.comb.numberOfCells

    property to “0” (zero). This will result in a solid rectangular border around the value area. You can do this on the PrePrint event, let it get printed as a rectangle, and then set the comb’s numberOfCells property back to whatever it was set to in the PostPrint event.

  22. Sérgio on November 27th, 2006

    Stefan,

    I think the comb will be useful to some object but not to others…

    Tell me, is it possible to control each of the 4 border of a field, in what relates to the content area border? For instance, is it possible to change only the color of one of it, or its appearance (visible or not)?

    Thank you

  23. Stefan Cameron on November 28th, 2006

    Sergio,

    You can, in fact, control all four edges of a border — even the roundness of each of the four corners — independently. You just need to know how to work with the

    border.edge

    element as XFA defines it.

    Basically, there can be up to four edge elements for each border element. Edges are defined from the top edge to the left edge in a clockwise motion. Therefore, edge[0] is the top edge, edge[1] is the right edge, etc.

    To set properties on a specific instance of the edge element, you can use the

    getElement(“name”, “instance”)

    method which returns the specified instance of an element. From there, you can set the specific edge’s color, presence, stroke, etc.

    For example, the following JavaScript turns a text field with a solid box content area border into a blue dotted underline border:

    TextField1.ui.oneOfChild.border.getElement(“edge”, 0).presence = “hidden”;
    TextField1.ui.oneOfChild.border.getElement(“edge”, 1).presence = “hidden”;
    TextField1.ui.oneOfChild.border.getElement(“edge”, 2).stroke = “dotted”;
    TextField1.ui.oneOfChild.border.getElement(“edge”, 2).color.value = “0,0,255”;
    TextField1.ui.oneOfChild.border.getElement(“edge”, 3).presence = “hidden”;

    Notice that only edge[2] remains visible since that’s the bottom edge.

    Note that you can’t set the individual edge properties when you’re using 3D strokes such as “lowered”, “raised”, “etched” or “embossed”. For those strokes, you must only set the first edge element since all edges must have the same stroke. For those, just use “…border.edge…”

    Finally, this applies to both the field border and the content area border.

  24. Sérgio on November 29th, 2006

    Stefan,

    That’s great. I tried the following alternatives: change color to the same as the container; change the presence and change the thickness of each border to “0in”. I will choose one of the last two. This will solve my problem… not to print some borders to paper… finally 🙂

    Thank you again for all your help!

  25. Sergio on November 29th, 2006

    Stefan,

    Unfortunatly, I´m back again to this question…

    I was trying to make the border hidden and show on the prePrint and postPrint events. I need to figure out if the object had a comb of defined on it or not. For that I used this:

    if ( obj.ui.oneOfChild.comb.numberOfCells == “0”) {}

    This code inside the prePrint and postPrint events works great.

    However, I tried to create a function in a script object to centralize the code. But it seems that the if statement modify in some way my object: if it is a simple text field, it will be combed of… it is very strange because I´m not setting the comb of property anywhere in my script.

    How can this be possible? Can be a bug?

    Thank you

  26. Stefan Cameron on December 2nd, 2006

    Sergio,

    That’s a little strange. I wasn’t able to reproduce your problem. Is it possible you had forgotten to use a double equality operator in your IF statement? Something like this:

    if (obj.ui.oneOfChild.comb.numberOfCells = “0”)

    would cause the comb element to be specified (thereby turning the field into a combed field) with zero cells and would resolve to “false” in the IF statement because “obj.ui.oneOfChild.comb.numberOfCells” would get the value “0” which would be implicitly converted to “false”.

    If that’s not the problem, then it’s possible that simply accessing the numberOfCells property on the comb element is causing the comb element to be specified. In that case, I would certainly agree that it doesn’t behave in the way one would expect it to. There is, however, a “safer” way to check if a field is combed: Since a field’s combed state is determined merely by the specification of the <comb> element inside its oneOfChild UI node, you could use the isPropertySpecified(name) method:

    if (obj.ui.oneOfChild.isPropertySpecified(“comb”))

    The method will return “false” if the <comb> element isn’t specified, signifying that the field isn’t combed.

    If it returns “true”, then you can proceed to check the numberOfCrells property to determine the number of cells in the comb.

  27. Sergio on December 4th, 2006

    Stefan,

    I´m sure I used 2 equal signs! But that is not problem anymore as the isPropertySpecified worked well.

    Thank you!

  28. Brandon on January 22nd, 2007

    Sorry to bother you guys with what may be an easy do, but I have researched this like crazy and didn’t find much help.

    I am creating a PDF form for school bus drivers to use for the Field/Sporting trips. What I am trying to calculate the total hours on the trip. The fields are start.time, break.time, and return.time (actually r.time since you can’t use the word return) I am trying to subtract the return time from the start time to ge the gross time, then subtract the time (in minutes) of break from the gross time to end up with the net time. The main problems that I have is there is not always is there a break time, and the other is that all time is figured in 15 min. intervals.

    For example:
    r.time = 20:05 rounded (20:00)
    start.time = 18:11 rounded (18:15)
    break.time = 00:34 rounded (00:30)

    So the result should be 1:45 converted to 1.75 hours.

    I have been trying, but getting some very strange results.

    Can anyine provide some help please?

  29. Stefan Cameron on January 28th, 2007

    Brandon,

    It sounds like you’ve got a challenge on your hands! Hopefully this little tip will help you out:

    In the FormCalc script language, there are two methods that can be used to do time-based calculations: Time2Num(time_value, format) and Num2Time(num_value, format).

    The first, Time2Num, takes a time value (which you would obtain from a date/time field with its Data Format — see the Binding tab in the Object palette — set to “Time”) and a time format (typically “HH:MM”, which you would’ve set as the time field’s Data Pattern) and returns a value representing the number of milliseconds since Jan 1, 1970.

    The second, Num2Time, takes a value representing milliseconds since Jan 1, 1970 along with a time format and returns the time in the specified format.

    Using these two methods, you can calculate the next 15 minute increment of time like this (in FormCalc on the Exit event of a field named “TimeField1”):

    // milliseconds in 1 minute
    var n1MinInMilli = 60 * 1000

    // milliseconds in 15 minutes
    var n15MinInMilli = 15 * n1MinInMilli

    // time entered translated into ms since Jan 01, 1970
    var nTimeValue = Time2Num(TimeField1, “HH:MM”)

    // advance to the next 15 min increment (must add an extra minute since Time2Num is zero-based)
    var nNext15MinInc = (Floor(nTimeValue / n15MinInMilli) * n15MinInMilli) + n15MinInMilli + n1MinInMilli

    // increase the entered time to the next 15 min
    TimeField1 = Num2Time(nNext15MinInc, “HH:MM”)

    If you put this script in a time field’s Exit event, the time will be increased to the next 15 minute increment when you exit the field, after entering a time value. For example, entering “11:37” would produce “11:45” and “04:14” would give “04:15” and so on.

    One last tip: If there’s no break (and therefore no time value entered into the “break.time” field), the “break.time” field’s value will be null. You can test for an empty field in FormCalc by using the HasValue(field) method: “HasValue(TimeField1)” will return true if “TimeField1” is null or empty.

  30. Erwin Michiels on February 19th, 2007

    Dear Friends,

    I am new [early beginner] in programming fields with LiveCycle!

    I am building an ‘everyday timing data sheet’ all related to every job we doing during the day.
    Building and/ or designing the main sheet with LiveCycle Designer is without any problem.

    My main problem is to find out what data I have to enter.
    We should have a ’start’ + ‘end’ + ‘total’ and ‘grand total’ time with 15 minutes fractions.

    Can somebody give me some answers and advice?!
    Any help is hard welcome!

    Thanks in advance,

    Erwin Michiels/ Indonesia

  31. Stefan Cameron on February 20th, 2007

    Erwin,

    Assuming you have Designer 7.1 or later, your time sheet might be a simple table with 3 columns per row: start, end and total. Then you might have a grand total field at the bottom of the table in a footer row.

    The total field in the table rows would have a simple Calculate script which determines the duration of time elapsed between the start and end time fields. If this needs to be in 15 minute fractions, the sample script i posted in my previous comment (to Brandon) should be a good starting point for calculating elapsed time in 15 minute increments.

    Finally, the grand total field would have a FormCalc Calculate script similar to this:

    Sum(total[*])

    This statement would assign the sum of all instances of the “total” field in the form to the grand total field.

  32. Chelsea on June 2nd, 2008

    Stefan,

    Unfortunately, I’ve seen several postings asking the same questions, but with answers that assume a higher level of proficiency than I currently have.
    We are attempting to create a timesheet with seven rows and five columns. The columns include starttime, endtime, breakstart, breakend, and totalhours, with a number following each designation (according to the line – ex: starttime1, endtime1, etc.). At the end of the row, I’d like to calculate the total number of hours.

    When I attempt to enter the FormCalc equation, it keeps giving me an error that it doesn’t accept the name of the field in the calculation. I think I’m just having difficulty entering the correct script. Do you have a suggestion for a script to enter?

    Also, if I have a drop down menu designating those hours as “Comp Time” or “Overtime”, is there a way to make then tabulate differently, so that the form can tabulate total overtime hours as well as total comp time hours?

  33. Stefan Cameron on June 7th, 2008

    Chelsea,

    I’m sure we can get this working for you however I would need to know how you’ve created your timesheet before I can recommend how you should write your script. Are you using a table where each column is a field that represents start time, end time, break start, etc.? If you aren’t using a table, are you using subforms and if so, how have you structured them (how are they nested)?

  34. Matt on June 24th, 2008

    I am very new to Adobe as well (8.0) I am using LiveCycle Designer to create a timesheet as well and this is over my head. I have developed a form, included in that form is a table 9 Columns: Day, Date, Time In, Lunch Out, Lunch In, Time Out, Paid Leave, Type of Leave, Total Hours Worked. Rows of course would include days of the week and the user would enter data for that particular date. I want to capture the total hours to include any paid leave taken. I understand that calculations have to take place but I can only seem to get funky results: Fields are data and time. Data pattern: HH:MM, data format: time

    My sample result for just one time calculation: Time In Displays 7:30AM, Lunch Out Displays 11:00AM and my total hours worked is 370 which is correct if you just subtract 1100-730. If I could just see a snipet of one time calculation and learn from it I should be able to do this. Any assistance on this would be greatly appreciated.

  35. Matt on June 25th, 2008

    Please disregard my previous post as I have figured out what to do.

    Is there a way to check the field for numeric only entries, I need to work on catch and error messages. I do not want a user to type a alpha character as a time entry.

  36. Stefan Cameron on June 25th, 2008

    Matt,

    I’m glad you got it to work.

    To prevent unwanted characters from being input into the field, you have to script the Change event and look at the xfa.event.change property which contains the character that the user has typed. Since this happens before the character is actually inserted into the field, you can essentially cancel the character input by setting that property to an empty string.

    Here’s a quick little sample, written in JavaScript, that excludes all non-numeric characters from the input:

    var newChar = xfa.event.change;
    var re = new RegExp("\\d"); // verify the character is a single digit
    
    if (newChar.match(re) == null)
    	xfa.event.change = ""; // cancel the character input
  37. Tom on July 14th, 2008

    Hi, I have two semi-related questions.

    I am wondering where I would insert a script tag to handle the main loading event of the PDF form. I am trying to run an SQL query to prepopulate a PDF form, but Adobe Reader seems to be caching older SQL query results. I want to be able to clear the cache, or clear the form then run the SQL query.

    Also, is there some way to pre-populate a form once with a query, then have usage-rights enabled so that a user can make small edits to the form if saved on there desktop? The PDF form is being served up on a web server. My webpage allows a user to search ID’s, then prepopulate the form based on the target ID.

  38. Stefan Cameron on July 20th, 2008

    Tom,

    You can use the Script Editor palette (“Window menu > Script Editor”) to script the forms Initialize event which is fired when the PDF is loading.

    You mentioned that “Reader seems to be caching old SQL query results.” I assume, then, that you’ve extended your PDF, using LiveCycle Reader Extensions, to allow for data import in Reader or that you’re using LiveCycle Forms to serve the form to the browser?

    As far as pre-populating a form with a query and then permitting the user to make edits and save it to their desktop, you would just ensure that your initialization script, that runs when the PDF is loaded, only runs once (e.g. if a particular field, that gets filled as a result of the query, is already filled, don’t let the query execute again). You can manually execute an ODBC data connection by using the open() method:

    if (can_run_query)
    {
        ...
        myDataConnection.open(); // execute query
    }
  39. Maria on January 31st, 2010

    can someone please help me . i need to know how to calculate the number of days between two different dates?
    Cheers,
    Maria

  40. Stefan Cameron on February 8th, 2010

    Maria,

    There are date and time functions available in both JavaScript (the Date object) and FormCalc (see the XFA spec for the FormCalc date/time functions) that you can use to calculate the number of days between two dates.

    In FormCalc, you would likely use the Date2Num function to convert the dates to numbers then determine the number of days represented by the subtraction of the first and second date.

  41. Rhonda on May 20th, 2010

    I’m creating a form and I want each space, after filling it in, to automatically jump to the next space without having to tab to it. Can you tell me how to do that?

    Thanks,
    Rhonda

  42. Stefan Cameron on May 31st, 2010

    @Rhonda,

    In order to do that, you would first have to determine what rule(s) determine that the user has finished entering a value in a field. You can check the value as the user enters it in the Change event and, if the rule(s) is(are) met, set focus to the next field by using the xfa.host.setFocus() function:

    xfa.host.setFocus({nextField}.somExpression);

    where {nextField} is the field to which focus should go.