Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

FormCalc Expressions (If and For)

In Designer, you can write scripts using one of two languages: FormCalc and JavaScript. If you’re like me, you’re more familiar with JavaScript because it’s very similar to Java and JScript syntax but when it comes to FormCalc, you’re lost. Well, not completely but you find it very difficult to find documentation on the syntax for loops (like While, For, etc.) which are sometimes essential. Maybe you fall-back on JavaScript in those times but, on average, FormCalc scripts execute much faster than JavaScript scripts so why not harness that performance in our forms?

In this post, I’ll explain the syntax of the If and For expressions in FormCalc. Those of you familiar with Visual Basic or VBScript will likely find this more familiar than the equivalent JavaScript syntax (while I’ll include for comparison however this isn’t a post on JavaScript syntax). In future posts, I’ll add to this collection by discussing the syntax for While and ForEach loops.

Conventions

Before we get started, I should explain a few things about the various syntax blocks you’ll find further down in this post (note that this is simplified for the purposes of this article):

  • SimpleExpression: A simple expression like a comparison “i >= 0” that evaluates to true or false or a single entity like “MyVar” (a defined variable) or “5” (a number), for example.
  • ExpressionList: A set of 1 or more expressions, each on a separate line.
  • Square Brackets: A series of keywords (like “if”, “then”, “for”, “while”, etc.), SimpleExpressions and ExpressionLists grouped within square brackets denote an optional part of the syntax.
  • Asterisk Character: Sometimes a closing square bracket is followed by an asterisk (*). This indicates that the optional syntax may be used 0 or more times.
  • Question Mark Character: Sometimes a closing square bracket is followed by a question mark (?). This indicates that the optional syntax must be used 1 or more times.

Variables

I assume you’re probably familiar with declaring variables in scripts but just in case, in FormCalc, you declare variables like this:

var MyVar

and you can even declare it and assign it a value in the same step:

var MyVar = 5

If Expression

Let’s look at one of the most essential of all expressions:

FormCalc Syntax

if ( SimpleExpression ) then
    ExpressionList
[ elseif ( SimpleExpression ) then
    ExpressionList]*
[ else
    ExpressionList]?
endif

Based on the syntax, you can do things like (assuming you’ve declared a variable named “i”):

if (i >= 10) then
  i = i + 10
endif

or

if (i >= 10) then
  i = i + 10
elseif (i >= 5) then
  i = i + 5
  i = i * 2
else
  i = i + 1
endif

Hopefully this illustrates the differences in the syntax indicated by the asterisk and question mark characters.

JavaScript Syntax

For comparison, let’s look at the equivalent JavaScript syntax for the two examples above (note the semicolons and curly braces):

if (i >= 10)
  i = i + 10;

or

if (i >= 10)
  i = i + 10;
else if (i >= 5)
{
  i = i + 5;
  i = i * 2;
}
else
  i = i + 1;

For Expression

Often times, in your scripts, you need to execute some statements a certain number of times or iterate through a collection. In those cases (and many others), a For loop may be useful.

FormCalc Syntax

for Variable = StartExpression
        (upto | downto) EndExpression
            [step StepExpression]?
        do
    ExpressionList
endfor

In this syntax, there’s a StartExpression, and EndEExpression and a StepExpression. These are all similar to SimpleExpressions as described earlier. One thing to note about For loops in FormCalc is that “upto” loop will iterate as long as Variable is less-than-or-equal-to (<=) EndExpression whereas a “downto” loop will keep iterating as long as Variable is greater-than-or-equal-to (>=) EndExpression. Also, the variable Variable is implicitely declared in the For expression.

Based on the syntax, you can do things like add the numbers 1 to 10, inclusively, to a list:

for i = 1 upto 10 do
  MyList.addItem(i)
endfor

and then

var nCount = MyList.#items[0].nodes.length

if (nCount >= 2) then
  for nItem = nCount downto 1 step 2 do
    xfa.host.messageBox( MyList.#items[0].nodes.item(nItem - 1) )
  endfor
endif

which would display the value of each even-numbered list item in reverse sequence using a message box as long as there’s at least one even-numbered list item to display.

JavaScript Syntax

For comparison, here are the equivalent JavaScript examples (note the semicolons and curly braces again):

for (var i = 1; i <= 10; i++)
{
  MyList.addItem(i);
}

(in this case, the curly braces are optional but I think this is better style) and then

var nCount = MyList.resolveNode("#items[0]").nodes.length;

if (nCount >= 2)
{
  for (var nItem = nCount; nItem >= 1; nItem - 2)
  {
    xfa.host.messageBox(
      MyList.resolveNode("#items[0]").nodes.item(nItem - 1) );
  }
}

Posted by Stefan Cameron on September 14th, 2006
Filed under FormCalc
You can skip to the end and leave a response. Pinging is currently not allowed.

8 Responses to “FormCalc Expressions (If and For)”

  1. Scott Sheck on May 4th, 2007

    I agree that it’s more readable to have brackets in the javascript IF statement even if it’s a single statement, but I prefer to hide the first bracket because then it reduces the lines of code to make it more readable for me.

    if (nCount >= 2) {
       for (var nItem = nCount; nItem >= 1; nItem - 2) {
          xfa.host.messageBox(
            MyList.resolveNode(”#items[0]“).nodes.item(nItem - 1) );
       }
    }

  2. Greg Blodgett on July 16th, 2007

    Not sure where to post this on this site so figured this looked best. I am trying to follow a tutorial you had posted a while back and cannot get it to work.
    Basically I need someone to choose a value from a drop down list (which is pulling from an oracle db). Then based on that drop down I want it to populate other fields on the screen. Right now I have 2 fields on the screen ZZ_CODE and ZZ_DESC. When they choose ZZ_CODE I want it to populate ZZ_DESC.
    Here is my script:

    —– form1.#subform[0].Body.ZZ_CODE::change: - (FormCalc, client) ———————————

    var sCODE = xfa.event.newText
    var sZZ_CODE = $.boundItem(sCODE)
    var oDataConn = Ref(xfa.sourceSet.AbraData)

    oDataConn.#command.query.commandType=“text”

    oDataConn.#command.query.select = Concat(“Select distinct ZZ_DESC from PS_ZZ_HRTABLES Where ZZ_CODE = “, sZZ_CODE,””)

    oDataConn.open()
    oDataConn.first()
    AbraSub.presence=”visible”
    AbraSub.ZZ_DESC = sCODE

    I get an Script Failed error - Error: syntax error near token ”

    If I can get this working I would then like to be able to take multiple fields into my where clause to populate the other fields on the form. For example, i will have a country code and a state code which will drive combined the data that shows on the form. So where clause like so ” Where state = “, sZZ_State,” and country = “,sZZ_COUNT,””)

    Any help would be greatly appreciated. In fact I could even fax you a beer! :)

  3. Stefan Cameron on July 21st, 2007

    Greg Blodgett,

    I’m wondering if the syntax error you’re getting is due to the double-double-quotes you have as the 3rd parameter to the call to the Concat function since in FormCalc, two double-quotes in a row evaluates to a single double-quote (that’s how you would get a double-quote into a string, for example).

    Since you’re only concatenating two strings, you don’t really need the 3rd parameter so just try it like this:

    oDataConn.#command.query.select = Concat("Select distinct ZZ_DESC from PS_ZZ_HRTABLES Where ZZ_CODE = ", sZZ_CODE)

    Let me know if that solves the problem. I’ll get my fax machine ready just in case… ;)

  4. Greg Blodgett on July 25th, 2007

    Stefan,
    I have completed mutilated my code since i posted. So now I have done this below going by what I found in Adobe documentation:
    I now do not get an error but my other fields are not updating. My drop down list is populating correctly but when I choose something nothing else changes on the screen.
    I am also getting an Oracle error listener could not resolve SERVICE_NAME. This error is odd because I can login through the Data View and it pulls back the tables but when I
    preview I get the Oracle error - weird…I will have to buy more beer for this one!

    —– form1.#subform[0].ZZ_EEID::initialize: - (JavaScript, client) ——————————–

    var sDataConnectionName = “AbraData”;
    var sColHiddenValue = “ZZ_EEID”;
    var sColDisplayText = “ZZ_EEID”;
    // Search for sourceSet node which matchs the DataConnection name
    var nIndex = 0;
    while(xfa.sourceSet.nodes.item(nIndex).name != sDataConnectionName)
    {
    nIndex++;
    }
    var oDB = xfa.sourceSet.nodes.item(nIndex).clone(1);
    oDB.open();
    oDB.first();
    // Search node with the class name “command”
    nIndex = 0;
    while(oDB.nodes.item(nIndex).className != “command”)
    {
    nIndex++;
    }
    // Need to set BOF and EOF to stay
    oDB.nodes.item(nIndex).query.recordSet.setAttribute(“stayBOF”, “bofAction”);
    oDB.nodes.item(nIndex).query.recordSet.setAttribute(“stayEOF”, “eofAction”);

    // Search for the record node with the matching Data Connection name
    nIndex = 0;
    while(xfa.record.nodes.item(nIndex).name != sDataConnectionName)
    {
    nIndex++;
    }
    var oRecord = xfa.record.nodes.item(nIndex);
    // Find the value node
    var oValueNode = null;
    var oTextNode = null;
    for(var nColIndex = 0; nColIndex

  5. Stefan Cameron on July 25th, 2007

    Greg Blodgett,

    Your script was cut-off because of a “less-than” character interpreted as HTML code. Please re-post your comment making sure that any less-than (”<”) characters are replaced by “&lt” (without the quotes).

  6. Greg Blodgett on August 8th, 2007

    Hope this works I tried another time and it still cut it off.
    Thanks for all your help. So Stefan are you available for consulting?

    —– form1.#subform[0].ZZ_EEID::initialize: - (JavaScript, client) ——————————–

    var sDataConnectionName = “AbraData”;
    var sColHiddenValue = “ZZ_EEID”;
    var sColDisplayText = “ZZ_EEID”;
    // Search for sourceSet node which matchs the DataConnection name
    var nIndex = 0;
    while(xfa.sourceSet.nodes.item(nIndex).name != sDataConnectionName)
    {
    nIndex++;
    }
    var oDB = xfa.sourceSet.nodes.item(nIndex).clone(1);
    oDB.open();
    oDB.first();
    // Search node with the class name “command”
    nIndex = 0;
    while(oDB.nodes.item(nIndex).className != “command”)
    {
    nIndex++;
    }
    // Need to set BOF and EOF to stay
    oDB.nodes.item(nIndex).query.recordSet.setAttribute(“stayBOF”, “bofAction”);
    oDB.nodes.item(nIndex).query.recordSet.setAttribute(“stayEOF”, “eofAction”);

    // Search for the record node with the matching Data Connection name
    nIndex = 0;
    while(xfa.record.nodes.item(nIndex).name != sDataConnectionName)
    {
    nIndex++;
    }
    var oRecord = xfa.record.nodes.item(nIndex);
    // Find the value node
    var oValueNode = null;
    var oTextNode = null;
    for(var nColIndex = 0; nColIndex &lt oRecord.nodes.length; nColIndex++)
    {
    if(oRecord.nodes.item(nColIndex).name == sColHiddenValue)
    {
    o
    ValueNode = oRecord.nodes.item(nColIndex);
    }
    else if(oRecord.nodes.item(nColIndex).name == sColDisplayText)
    {
    o
    TextNode = oRecord.nodes.item(nColIndex);
    }
    }
    while(!oDB.isEOF())
    {
    this.addItem(oValueNode.value, oValueNode.value);
    //IDList.addItem(oValueNode.value, oTextNode.value);
    oDB.next();
    }
    // Close connection
    oDB.close();

    —– form1.#subform[0].ZZ_EEID::change: - (FormCalc, client) ————————————–

    var sZZ_EEID = xfa.event.newText
    var oDataConn = Ref(xfa.sourceSet.AbraData)

    oDataConn.#command.query.commandType=”text”

    oDataConn.#command.query.select = Concat(”Select * from SYSADM.PS_ZZ_RATING Where ZZ_EEID = “, Ltrim(Rtrim(sZZ_EEID)))

  7. Stefan Cameron on August 8th, 2007

    Greg Blodgett,

    Your comment got flagged as spam. I suppose it was because of all the script. Luckily it was long enough that I noticed it as I was skimming my spam list (I get hundreds per day). :)

    I will try to respond as soon as I can.

    As for consulting, I’m not available for that unless you catch me at a conference… Otherwise, my primary duty is development on LC Designer and this blog is just something I run on the side. I can recommend a consulting service if you like.

  8. Stefan Cameron on August 14th, 2007

    Greg Blodgett,

    As far as I can tell, you Initialize script looks OK. As for your Change script, based on what you posted, you’re missing the following statements after you set the data connection’s select statement:

    oDataConn.open()
    oDataConn.first()

    That should explain why fields bound to the second data connection remain blank after you select an item in the drop down list.

    Also, if you are editing this form with Designer 8.0 and have saved is as an Acrobat 8 PDF (XFA 2.5) form, then you also have another problem with your Change script: You’ll first need to clone the data connection before you set its commandType and select properties. Otherwise, you’ll get a security error.

    Please give these tips a try and let me know if you get your form working.

Leave a Reply

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

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