Calling FormCalc Functions From JavaScript

For form calculations, validations and general scripting problems, our form designers can choose between using FormCalc and JavaScript. FormCalc was designed as an expression grammar targeting forms functionality — and designed to be easy to use for a novice form author familiar with expressions in Excel.  JavaScript on the other hand, is a much more general purpose and powerful scripting language.  Over time, form authors have gravitated more toward JavaScript, mainly because of its familiarity.  However, there are functionality gaps — specifically a set of built in functions that are available in FormCalc but not in JavaScript. 

Many of the built-in FormCalc functions can be easily mimicked in JavaScript.  It doesn’t take a rocket scientist to write a JavaScript script object function to imitate the FormCalc sum() function. However, there are some functions that are not so easily mimicked.  The most notable of these are the Parse() and Format() functions available in FormCalc.  Parse() and Format() are the entry points into the very rich picture clause processing functionality.  When you consider the inherent locale handling, date/time functionality, different calendars etc. it’s plain to see that you don’t want to do this in JavaScript.

But now we have a problem.  Many users are committed to JavaScript because they built frameworks for controlling validations and other form behaviours.  I did the same in the series of blog posts on validations (the most recent version of the framework was in the sample from this post).  The problem is that you cannot directly call FormCalc from JavaScript.  So it would seem that you can’t enjoy both the power and familiarity of JavaScript as well as the built-in functions of FormCalc.  Well, … actually you can.

There are two design patterns I’d like to cover:

  1. Validating fields with picture clauses
  2. General mechanism for calling FormCalc functions

Validating Fields with Picture Formats

Picture clause validations are a simple, declarative mechanism for form authors to ensure that input data complies with a specific format.  If the field value can successfully be formatted with the validation picture clause, then the field is considered valid.  e.g. if your validation picture clause is "Date{YYYYMMDD}", then the field is considered valid only if its value can be formatted as a date.  If you were to express this validation as a script, you could write this FormCalc expression:

form1.#subform[0].DateTimeField1::validate – (FormCalc, client)
format("YYYYMMDD", $) <> ""

Now the question is how to tap into this functionality from JavaScript.  The short answer:

  1. Define a *display* picture format (do not a validation picture format)
  2. Write a JavaScript validation script that returns true when the field.rawValue is different from field.formattedValue

Most often when you use a validation picture clause you also use a display picture.  In fact, there’s really no reason why these picture clauses need to be different.  Combine that knowledge with an understanding of how the field.formattedValue property works:  when a field value can be formatted using the display picture, field.formattedValue will return the result of the format operation.  If the format operation fails, field.formattedValue returns the same as field.rawValue.  So to find out if a field was formatted correctly, use this JavaScript validation:

form1.#subform[0].DateTimeField1::validate – (JavaScript, client)
this.rawValue != this.formattedValue;

Mechanism for Calling FormCalc Functions from JavaScript

The solution is to use the execCalculate() method to indirectly cross the bridge between JavaScript and FormCalc.  When you open the attached sample, you will find a subform called "fc" that holds a script object called "func".  "func" has a series of embedded JavaScript functions that mimic the FormCalc functions with the same name.  Each function populates form variables with the function name and input parameters.  It then calls execCalculate() on the fc subform and returns the resulting value:

FCfromJS.fc.#variables[0].func – (JavaScript, client)
function Format(vPicture, vValue)
{
    F.value = "Format";
    P1.value = vPicture;
    P2.value = vValue;
    this.execCalculate();
    return ResultString.value;
}

The subform calculation script looks like this:

 FCfromJS.fc::calculate – (FormCalc, client)
; execute the requested function based on the input
; request parameters
if (F == "WordNum") then
    ResultString = WordNum(P1)

elseif (F == "Parse") then
    ResultString = Parse(P1, P2)

elseif (F == "Format") then
    ResultString = Format(P1, P2)

elseif (F == "Uuid") then
    ResultString = Uuid(P1)

elseif (F == "UnitValue") then
    ResultString = UnitValue(P1, P2)

else
    ResultString = ""
endif

The field that wants to use the format() functionality has a simple calculate script:

FCfromJS.#subform[1].format.Result::calculate – (JavaScript, client)
fc.func.Format(PictureClause.rawValue, Value.rawValue);

This fc subform can easily be incorporated as a custom library object in Designer that can be dragged onto any form.  It should be pretty easy to follow the design pattern if you want to extend the sample and add other FormCalc functions.

One usage note — if you want to call these functions from initialization scripts, then be sure to place the fc subform at the beginning of your template.  This is necessary because the fc subform has an initialization script that creates the necessary form variables.  By placing this subform at the top of the form hierarchy, we’ll be certain that the fc initialization event fires before other initialization events.

August 12, 2009 Update

I have updated the sample form:

  • Added access to the formcalc Get() function. 
  • Added a version checking mechanism (see this post for details).
  • The subform housing this functionality is now available as a downloadable fragment: scFormCalc.xdp
  • The functionality is accessed using the subform "enter" event rather than the calculate.  The calculate event was introducing unwanted calculation dependencies.

4 Responses to Calling FormCalc Functions From JavaScript

  1. Bruce says:

    Thank you for providing this sample, I have found this very useful and it has saved me a lot of time with my validations.I was wondering if you could point me to some documentation regarding the Format function. I have looked in the “FormCalc User Reference” and the “Picture Clause Specification Version 2.0” document but neither seem to describe the format pattern you use in your example. That is the “zero{‘zero’}” part of the Format() function picture clause. I was hoping to use something similar for null values, something like “null{‘unknown’}”, is this possible?

  2. Bruce:I’m glad to hear you’re making good use of this technique. You’re in luck, null{‘unknown’} should work just fine. These special categories are described in the picture clause spec on page 1094 of the XFA 3.0 specification.John

  3. Bruce says:

    Thanks for the picture clause spec link which was very helpful with another of my problems. But I still have a problem with the null values as the Format function in the func script object passes the value to the calculate event via the P2 text object (as you obviously know). The text object does not seem able to be set to null. So I keep getting the result of the previous call to the Format function.My hack to fix this is to look for the Null-category picture clause myself by adding the following two lines at the start of the Format functionvar result = vPicture.match(/null{‘(.*)’/);if (result) return (result[1]);I’m hoping you will have a better solution.

  4. Bruce:Very good point. The null value was not preserved when passed to FormCalc using a form variable. I’ve posted an updated version of the form that uses another form variable to track the null state of the input value. You should be able to pass in null values now.John