Creating Basic Form Rules

Form rules are pieces of JavaScript code that let you define how users interact with your basic forms. You must be familiar with the JavaScript to create and edit form rules.

JavaScript Syntax for Basic Form Rules

Basic form rules are pieces of server-side JavaScript code that let you determine how users interact with your basic forms by defining how basic form controls are displayed and the types of data users can enter.

You can use basic form rules to define the behavior of a basic form. Typical uses of basic form rules include:

  • Adding dynamic behavior to a basic form, including showing or hiding elements or enabling or displaying elements.

    For example, you can add basic form rules that show or hide certain form controls or entire sections based on the state of other form controls. Displaying form fields in a context-sensitive manner reduces clutter and makes it easier for users to navigate your basic forms.

  • Performing complex calculations.

    For example, you can compute the total invoice price on an order form from values of other form fields such as item quantity and price.

  • Performing complex validations.

  • Populating a dynamic drop-down list.

    For example, you can retrieve a list of values for a drop-down list from a REST service. Retrieving values from a secured service requires you to create a security key credential. See Configuring Credentials for Web Services.

General Format and Guidelines

In Oracle Process Cloud Service, a basic form rule is expressed in JavaScript code. Basic form rules are saved and can be run after you save your application.

Basic form rules generally have the following form:

if (condition)
{
   true actions;
}
else
{
   false actions;
}

You can create more advanced basic form rules primarily for the purpose of looping over repeating items. Here are some basic characteristics of JavaScript that you must be aware of when writing basic form rules:

  • Case-sensitivity: JavaScript commands are case-sensitive.

    For example, var color1 and var Color1 are two different variables.

  • Loosely typed variables: In JavaScript variables are loosely typed.

    Variable types don't have to be explicitly declared. For example, var color = 'red'; and var num = 33 cause the variable color to be a string type and num to be a numeric type.

  • End of line semicolons: End-of-line semicolons are optional.

    However, you should use semicolons to terminate lines as part of good coding practice. This often prevents mistakes.

  • Comments: You can add comments to your code using either // or /* */ syntax.

Oracle Process Cloud Service doesn't support the following JavaScript syntax:

  • switch statement

Oracle Process Cloud Service does support the following syntax with some limitations:

  • try-catch

    For example, in the following example, the value of the control named FN is set to 'got exception' because the JavaScript variable named x is undefined in this basic form rule:

    if (form.load) {
        try {
            x.randomproperty = 'blah';
        }   catch (e) {
            FN.value = 'got exception';
        }
    }

    However, catching an exception when a form control isn't defined isn't supported and may behave unexpectedly. This is because Oracle Process Cloud Service catches the problem while parsing the basic form rule before the JavaScript interpreter catches the error.

    In the following example, the control named Color doesn't exist in the form.

    if (form.load) {
        try {
            Color.value = "red";
        }   catch(e) {
            msg1.value = "error caught: " + e;
        }
    }

Control Name

Basic form rules often must reference form controls. You must assign a control a name using the control's name property.

Names are case sensitive. If your control is named FirstName then you must write the basic form rule as FirstName.value. firstname.value doesn't work.

When using a control in a basic form rule, you must ensure that the control has a unique name. If multiple controls have the same name, the run time environment can't determine which control the basic form rule refers. Form controls added to a form from the palette are usually guaranteed to have a unique name. The basic forms designer doesn't allow you to change the name of a control to one that already exists in your form.

However, there are several contexts where you can have multiple controls with the same name:

  • Controls added from XSD data sources

  • Controls added from the custom palette

  • Controls nested in sections

If there are two controls with the same label and at the same level, the control name is automatically made unique. If you try to edit the name such that it’s no longer unique, the basic forms designer prevents you from making the change.

When a control is dropped inside a section control, it’s at a different nesting level then a control dropped outside a section. Two controls, one inside a section and another outside the section, are also at different nesting levels. The basic form designer allows you to provide identical names to the controls.

If non-uniquely named controls are used in basic form rules there may be unexpected results. If you encounter errors in a form, you can edit the names of control names to make them unique.

Note:

Editing the name of a from XSD schema control has no effect on the XML instance document created when the form is submitted nor on the XML validation.

Basic Form Rule Identifiers

Basic form rules refer to form controls using the Name property. If you have a control where the Name property is defined as MyControl, you can refer to properties of this control in basic form rules using the name as an identifier.

Form rule identifiers must always be of the following form:

Name.<property>

These basic form rule identifier properties are supported:

  • Visible: Set to False to hide a control and True to make the control visible.

  • Value: Read or set the value of a control.

    This property isn't applicable to sections, tabs and other controls that don't have values displayed to the user.

  • Enabled: Set to False to disable a control so that a user can’t change its value and set to True to enable it.

    This isn't applicable to sections and tabs.

  • Expanded: Set to False to collapse a group control (sections controls only) and set to True to expand a group control.

  • Selected: Set to True to designate a tab as the selected tab. (tab controls only).

  • Valid: The value of this property is True if the control contains a valid value otherwise its value is False.

    Validity is based on the control's type. For instance, a numeric control is invalid if the user enters a string value that can't be converted to a number. This property can be set and read.

  • Required: Set to True to make a control required and display the red asterisk.

    This property only affects palette controls and not controls generated from XSD schema data source.

    This property is also valid for section controls. Setting a section required to False automatically sets all inner controls to not required.

  • Options: Enables dynamic setting select control options (radio, drop-down and check box controls only).

  • Label: Sets the label seen on any control including sections.

  • Help: Sets the help text.

  • Hint: Sets the hint seen on hover.

  • Status: Sets the error message display whenever the control's value is invalid.

  • Clicked: Used by the trigger controls. Its initial state is False.

    When a user clicks a trigger its state turns to True.

  • Printable: Set to False to remove the control from both the printable view and PDF submission document.

  • itemAdded: Used by repeat controls. Its initial state is False.

    When a user clicks "+" to add a repeat item AND when a repeat item is added through a Document URI as the form loads, its state turns to True.

  • itemRemoved: Used by repeat controls. Its initial state is False.

    When a user clicks "-" to delete a repeat item, its state turns to True.

  • itemIndex: Used by repeat controls.

    When an itemAdded or itemRemoved event fires, the value of itemIndex is set. For itemRemoved events itemIndex returns -1. For itemAdded events itemIndex gives you the index of the added item.

  • form.load: This property is set to True when the form is first loading.

    Its useful for setting default values through basic form rules that must be set before the user starts interacting with the form.

  • form.unload: This property is set to True when the users clicks the form's Submit button.

    Its useful for setting control values just prior to when the form's Doc Actions and Form Actions are executed.

Examples of identifiers used in basic form rules are:

  • FirstName.value

  • BillingAddress.visible

  • Email[1].value

  • Email[i].visible

The latter two are examples of repeating controls. Repeating controls are discussed in more detail later. Note that the case of the properties is important. FirstName.value is a valid basic form rule identifier but FirstName.Value or FirstName.vAlUe aren't.

Strings and Numbers

Because JavaScript is a loosely typed language there may be situations where you must add field values and the basic form rule performs string concatenation instead. There are several ways to tell the basic form rule to perform mathematical calculations instead of string manipulation. One simple way is by adding a *1 to the variable. id = id*1 + 1; ensures that id equals the current value plus one rather than the current value with a 1 appended. For example, if the current value is 4 and you didn't write id*1 the result may be "41" rather than 5.

You may also encounter a situation in a basic form rule in which money controls perform a string concatenation rather than addition. To correct this:

  • Open the form with the basic form rule in the designer, change the money controls to text controls, then save the form.

  • Open the form, change the text controls back to money controls, then save the form again.

Dates and Times

To initialize a date control, the data must be in the correct format.

Here are some examples of correct date formats:

  • d1.value = "2012-01-13"; //yyyy-mm-dd

  • d2.value = "01-13-2014"; //mm-dd-yyyy

  • d3.value = "jan 13 2014"; //using string for month

In general, it’s not recommended to rely on either the browser's locale or the server's locale when writing date, time (time of day) and date/time literals in rules.

An example date and time rule follows:

if (form.load) {
   date.value = "2014-02-29";
   timeofday.value = "13:10:02";
   datetime.value = "2014-02-29T18:10:02Z";

This rule initializes a date control in a form with 02-29-2014, a time control with 1:10 PM and a date and time control with 02-29-2014 in the date portion and 1:10 PM in the time portion.

Notice the special character "Z" at the end of the date/time value. This is equivalent to an offset of UTC-00:00 and indicates that the time of 18:10:02 is given in UTC. 18:10:02 UTC is equal to 1:10 PM Eastern Standard time in UTC.

Time and date/time controls also require correct formatting and an understanding of how basic forms manage time zones. Basic forms convert times into the browser's local time zone before displaying them in the form. However, if time data isn't correctly formatted, basic forms make multiple attempts to parse the time but always displays the time with NO time zone conversion. Here are examples of correct time formats:

  • t1.value = "20:30:00";

  • d2t2.value = "20:30:00Z";

  • t3.value = "20:30:00-04:00";

  • dt1.value = "2012-08-23T20:30:00";

Writing Conditions

One of the most common conditions is a form rule that executes as soon as the user enters a value in the control. The test for this condition depends on if the field is a string type or a numeric type.

String Types: text, textarea, date, phone

if (name.value.length > 0)

Numeric Types: money, quantity, number

if (name.value != null) or if (name.value > 0)

are both common test conditions.

Many times the condition name.value.length > 0 can be dropped altogether and the basic form rule can be simplified. This basic form rule executes whenever a user enters a value into either the control named firstname or lastname.

fullname.value = firstname.value + ' ' + lastname.value;

Select Controls

Radio controls, drop-down lists, and check boxes are all examples of select controls.

Radio controls and drop-down lists are single select. Users can select only one item from the radio controls or in the drop-down list at a time. Thus, the ID.value of radios and drop-downs is similar to the other input and output controls. The value is a single item.

Check box controls are multi-select. Users can select multiple items at any given time. Thus, the ID.value of a check box is an array. For check boxes, a valid expression is ID.value.length, which returns the number of items in the value array. ID[0].value retrieves the fist item in the list, ID[1].value retrieves the second item, and so on. If you have a check box control with only one check box and that check box is unchecked, then the array contains no elements. For a check box control a useful expression is ID.value.length == 0. Note that ID.length isn't a valid expression. Also, because a check box control is an array it isn't a valid expression to write ID[0].value == . This is because if an option in the check box control is unchecked, its value isn't an empty string. It simply doesn't exist in the array.

Initial Control State

Every control in your form has an initial default property state for the visible, expanded, value, valid, and enabled properties. However, you can change controls in the initial state in the form designer Edit tab. An initial state of a control can be modified several ways. One way is by simply tying a value into an input control. This sets the default value for the control when the form is first opened in use mode. Another way is by expanding or collapsing group controls. This sets the initial expanded state. The default state for the visible and enabled properties is set through the controls edit property pane. The Edit property contains check boxes for visible and enabled for controls on which those properties make sense like input controls.

Basic Form Rules and Repeating Controls

If you have a repeating control in a form that itself contains a repeating control, you can't apply a basic form rule to the inner repeating control, since there's no way to tell which of the inner repeating items goes with which outer repeating item.

Additional Examples

See Basic Form Rule Examples.

Creating a Basic Form Rule

Oracle Process Cloud Service Composer provides an editor that lets you create and edit a basic form rule.

To create a new basic form rule:
  1. Open the form where you want to create a new form rule.
  2. Click Rules located on the toolbar.
  3. Click Create New Rule, click Edit, and then edit these fields:
    • Name: Defines the name of the basic form rule. Change this to something meaningful.

    • Enabled: Select to enable the basic form rule within your form. If you deselect this option, the basic form rule isn't applied to the form at runtime.

    • Description: Provides a description of the basic form rule. Modify the default to describe the behavior of the basic form rule and how it functions within the context of the form controls and other basic form rules within the form.

    • Rule: Defines the form rule.

  4. Click Edit located on the toolbar to return to the basic forms designer.
You can test the behavior of basic form rules while testing a basic form. See Previewing a Basic Form.

Using Dynamic Content

Real forms often require dynamic content in drop-down lists. Often based on the value entered into one form field, the values in other fields or options available in select controls must be dynamic.

Basic form rules enable invocation of HTTP gets that return X-JSON headers with JSON objects. This allows complete flexibility in assignment of default values populated into form fields such as text controls and select (radios, drop-down, check box) controls. You can also use http.post(), http.delete(), and http.put() in basic form rules, although you must use URL parameters with them, as they don't all support payloads.

Here is an example that shows the syntax of the http.get. This basic form rule invokes the http get, which must return a JSON object. The method on the servlet can do whatever necessary, such as querying a database given the itemName to retrieve the itemPrice. In this example the JSON object returned contains a field called price. The eval converts and assigns the JSON object to the JavaScript variable x. You can then use x in the basic form rule as necessary. In this example, it’s used to set a value to the form field called Price.

eval('x=' + http.get('http://<webhost>/test/json/getPrice?itemName=' + itemName.value));
Price.value = x.price;

Another example is where the JSON object returned in the http.get response contains an array called clients. This array can then be used to set the options in a drop-down list.

eval('x=' + http.get('http://<webhost>/test/json/getClients'));
Clients.options = x.clients;

Here is another example of a servlet that returns a JSON object after authenticating a user and password.

@Override
public void doGet (HttpServletRequest request, HttpServletResponse response)
       throws ServletException, IOException
{
   try {
       String u = request.getParameter("username"); 
       String p = request.getParameter("password");
       if (authenticate(u, p) == null)
           response.addHeader("X-JSON", "{auth:false}");
       else
           response.addHeader("X-JSON", "{auth:true}");
   } catch (Exception e) {
       throw new ServletException(e);
   }
}

This servlet can be used in a form rule as follows:

if (signForm.clicked)
{
   eval('x=' + http.get('http://<webhost>/MYservices/signForm?username=' + u.value + '&password=' + p.value)); 
   if (x.auth)
   {
      m.value = "<center>Authenticationn Succeeded</center>";
      }
}

It’s important to note that the http.get is accessing your HTTP service through a URL. Certain characters must be encoded in order to correctly pass through an HTTP URL You may not always be able to control the values your users enters into your form fields. If the value may contain one of these characters that value must be encoded.

For example, this http.get contains a password parameter. Since user passwords may contain characters such as '#' you should encode the value. The built-in JavaScript method encodeURIComponent() makes this easy.

eval('x=' + http.get('http://<webhost>/MYservices/signForm?username=' +
                     u.value + '&password=' + encodeURIComponent(p.value)));

You may also have to decode the URL parameter in your HTTP service. For example:

import java.net.URLDecoder;
String p = request.getParameter("password");
p = URLDecoder.decode(password, "UTF-8");

Reusing Dynamic Content

Fetching dynamic content from your back end system can be the source of degrading form performance. If your form must use the dynamic content multiple times you can improve performance by fetching the content once from the http.get() and saving the returned JSON string in a hidden text form control. You can then later read the text control value and eval it again rather than having to call your back-end system multiple times.

For example, add a hidden text control to your form named jsonUserData. Add a single line to the basic form rule that retrieves the user data from your back-end system through the http.get():

jsonUserDate.value = x;

In other basic form rules that also require the user data, rather than calling http.get() to your back-end system again, add the following line to your basic form rule:

var val = jsonUserDate.value;
   eval('x' = val);

This has the affect of setting x to the same string as if you had again fetched content from your back-end system.

Using Dynamic Validation

You can now perform dynamic basic form validation based on what action is being taken in Workspace.

Workspace passes the action name as a parameter and the JavaScript passes it to the basic form rule. The basic form rule decides whether the form data is valid or not based on the action.

To use dynamic validation:

  1. Create a text control with the name _action in your basic form and make this field hidden.

    Note:

    At runtime, the value of this field is set based on the action selected by the user.
  2. Write a rule that can do validation based on the value of _action. For example:

    .
    if(_action.value === "APPROVE")
    {
       email.required = true;
    }
    else
    {
       email.required = false;
    }
    . 

In this example, if the user clicks on Approve, then the form makes email required. If the action taken is anything other than Approve, then email isn't required.

Using Built-In Data

Oracle Process Cloud Service provides certain data to your basic form rules. This includes the Id of the person currently using your form. You retrieve this data in your basic form by calling var user = decode(subject.id); .

To obtain other user attributes, you can use Oracle BPM Rest Identity Service. Assume you have a text field named UserLastName and you want to populate it with the logged in user's last name. You can accomplish it by using the following basic form rule.

You can use a form.load basic form rule to pre-populate fields in your form with information about the currently logged in user. For example, if you have controls in your form named ID, FirstName, LastName, Email and Roles.

if(form.load)
{
   var loggedinUser = decode(subject.id);
   eval('user=' + http.get('http://host:port/bpm/api/1.0/identities/user/' + loggedinUser));
   UserLastName.value = user.userLastName;
}

Using Built-In Methods

Oracle Process Cloud Service provides built-in helper methods for common functionality required by basic form rules.

The following is a list of available methods for working with dates and times:

  • Time frevvo.currentTime(form): Returns the current time in the user's local time zone.

    This method should only be used to set the value of a Time control.

  • Date frevvo.currentDate(form): Returns the current date in the user's local time zone.

    This method should only be used to set the value of a Date control.

  • DateTime frevvo.currentDateTime(form): Returns the current date and time in the user's local time zone.

    This method should only be used to set the value of a Date/Time control.

Here is an example of setting a Time control named Tm, a Date control named Dt, and a Date/Time control named DtTm.

Tm.value = frevvo.currentTime(form);
   Dt.value = frevvo.currentDate(form);
   DtTm.value = frevvo.currentDateTime(form);

The currentTime(), currentDate() and currentDateTime() doesn't work in a form.load basic form rule unless you specify a time zone on the form's URL through the _formTz Url parameter. This is because the form server must know the time zone in which to return the date and time. If you don't specify a _formTz the methods return null and the control values remain blank. For example, to specify Eastern time: &_formTz=America/NewYork.

Use the following methods to work with users and roles:

  • boolean isUniqueUserId (String userId, String tenantId): Returns True if this user doesn't exist in the tenant and False if it does.

  • boolean isUniqueRoleId (String roleId, String tenantId): Returns True if this role doesn't exist in the tenant and False if it does.

Testing and Debugging a Basic Form Rule

When you create or edit a basic form rule, Oracle Process Cloud Service determines the list of controls and properties of those controls that the basic form rule depends upon. The basic form rule is automatically executed whenever there is a state change that is relevant to the basic form rule. Form rules are also executed sequentially in a top to bottom order as they're seen in the form rules pane.

Basic form rules can trigger the execution of other basic form rules. So, if a basic form rule, R1, sets the value of a control with Name A, and there is a form rule R2, that depends on A.value, then basic form rule R2 is triggered and executed.

A basic form rule typically refers to one or more form controls and their properties, and is executed if any of those properties change value. Basic form rules aren't fired when the page is loaded; for example, the following basic form rule is only executed when N1.value changes its value.

if (N1.value > 0 || N2.value > 0) {
   T.value = N1.value + N2.value;
}

Assume a use case where you want to show a message when a user enters an invalid Email. The form has a required Email input control (Name=E) and an action should be executed if the Email control valid property is False. You can write the basic form rule as:

if (!E.valid) {
// code to show message here.
}

The previous code doesn't work as expected as E is a required field and therefore E.valid initial value is False since the field is initially empty. When the user enters an invalid Email address, E.valid still has the value False and the basic form rule can’t execute since there’s no state change. The following code works properly:

if ((E.value.length > 0) && (!E.valid)) {
// code to show message here.
}

The basic form rule depends on both the value of E.valid and E.value.length and therefore, when a string longer than zero characters is entered the basic form rule is executed and the message is shown.

About Infinite Loops

It’s easy to create basic form rules that enter a loop condition. For example, a basic form rule that updates A.value based on B.value and another basic form rule that updates B.value based on A.value. They can continually trigger each other.

Oracle Process Cloud Service prevents this from happening by setting an execution time limit for each basic form rule. Any basic form rule that takes longer than 5 seconds to execute is forcibly stopped. This is a very lengthy period of time for most computational tasks and the vast majority of basic form rules aren't impacted by this constraint. However, since Oracle Process Cloud Service is a hosted site that may be simultaneously used by numerous users, there is a time limit imposed on these computations.

Debugging Duplicate Control Names

When you're designing forms, the forms designer generally prevents you from giving controls duplicate names, but you can give controls the same name if the controls are contained within different section controls. For example, you can have two sections in a form named Home and Office, and each section can have a text control named Address. However, if you want to use either of the Address controls in a basic form rule, you must give them unique names.

One way to tell if a basic form rule is breaking because of duplicate names is to look at the error sign in the Tomcat console. If you see a message similar to the following, it’s probably a duplicate control name problem.

16:50:35,390 WARN RuleObserver:455 - Error evaluating rule [Translate.Translate Form Rule]: Java arrays have no public instance fields or methods named "value." ([Translate.Translate Form Rule]#2) if (form.load) {Name.value = 'Nancy';}

The phrase Java arrays have no public instance fields or methods... is Java interpreting the controls with the same name as an array, not single controls.

About Basic Form Rule Profiling

Basic form rule execution can be profiled to determine how much time each basic form rule takes to execute. This can help you tune and improve performance in forms that use a large number of basic form rules. To turn on profiling set the rule-debug=profile on the URL.

If your basic form rules are executing database queries to populate dynamic select controls (drop-down, radio, check box), basic form rule profiling can help you identify if the database queries are taking too long. You may see HTTP calls taking a long time to execute.