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.


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) );
}
}
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! :)
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:
Let me know if that solves the problem. I’ll get my fax machine ready just in case… ;)
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
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 “<” (without the quotes).
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 < 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)))
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.
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:
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.