Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Rules are probably best described by using examples. This chapter contains numerous real world samples.

...

Table of Contents
maxLevel12

Calculate a Total

You have a form with three controls and you have assigned them Names N1, N2 and T respectively. When the user enters a value in either N1 or N2 you want to set the value of T to the sum of N1 and N2. The rule would be written as

Code Block
language
languagejavascript
themeConfluencejavascript
T.value = N1.value + N2.value;

...

Show/Hide Manager Approval

You have a flow and the first form has a Section for manager approval. The Section is hidden by default. Here is an example of a rule that makes the section visible in the second step of the flow which is a linked activity assigned to the manager role. 

Code Block
if (form.load) {
  var an = _data.getParameter ("flow.activity.name");
  if (an === 'Manager' || an === 'VP'){
    ManagerApproval.visible = true;
  } else {
    ManagerApproval.visible = false;
  }
}

...

Code Block
languagejavascript
if (ExpenseRepeat.itemRemoved) {var x;} 

Textarea Max Length

In html there is no way to set a maxLength on a textarea control. This is why the textarea control does not have a maxlength property like the text control does. It is possible to do this via a business rule. This example form has a textarea control named 'Desc' where the user can enter up to a 500 character description. On this control we also set the ErrorMsg property to the string 'You must limit your description to 500 characters'. This message is automatically displayed when the description control is set to invalid by the following business rule.

Code Block
if (Desc.value.length > 500) {
  Desc.valid = false;
} else {
  Desc.valid = true;
}

You can even customize the error message by adding this line to your rule. Now the error message will tell the user how many characters they are over the maximum allowed.

Code Block
Desc.status = 'Invalid. Max 20 chars allowed and you have ' + Desc.value.length; 

Textarea newline vs break

Users typically enter multi-line text into textarea controls. If you want to display that text in an html context, for example on a web page or in an html formatted email or in your form's Form Action display message you will need to replace newlines with html breaks. This caused by the fact that line breaks entered into a web form textarea are represented by a single newline character \n while line breaks in an html context are represented by the html break characters.

Our example has a textarea control named Description and a hidden control named DF. The user types into the visible control named Description and a business rules converts the newline characters \n into html breaks.

Code Block
languagejavascript
var x = Description.value; 
x = x.replace(/\\r/g,"");
x = x.replace(/\\n/g,"<br/>"); DF.value = x;

Dropdown Options

This example automatically sets the option selected in one dropdown based on the option selected in another. This is often useful when you have a form with choices that were dynamically populated. For example, imagine product choices which are descriptive text. When the user selects a product, your form needs to perform an action based on a product ID rather than the descriptive product text. A nice way to do this is to have the rule that dynamically populates the product choices dropdown also populate a product ID dropdown which remains an invisible control in the form. The product choices dropdown control was named Products and the product ID dropdown control was named PID

The 1st rule "Load Products" populates both the visible and hidden dropdowns with options from a database.

Code Block
/*member description productId resultSet */
var x;
 
if (form.load) { 
eval('x=' + http.get('http://localhost:8082/database/products'));   
 
    var opts1 = []; 
    var opts2 = []; 
 
    for (var i=0; i < x.resultSet.length; i++) { 
        if (x.resultSet[i]) { 
            opts1[i] = x.resultSet[i].description; 
            opts2[i] = x.resultSet[i].productId; 
    } 
} 
 
 
Products.options = opts1; 
PID.options = opts2; 
Products.value = opts1[0]; // default to 1st product option 
PID.value = opts2[0]; 
}

Finding a Selected Options Index

The 2nd rule Select Product ID keeps the hidden PID dropdown syncronized with the visible Products dropdown.

...

languagejavascript

...

Formatting money values to display in a Message Control

Let's say you have calculated a sum in a Number control in your form and you want to display it in a Message control and format it as a money value with commas and decimal places.  You will need a Number control named Num and a message control named Message in your form. This rule will display the number entered in the number control with commas. If the user enters 5600.44 in the number field then the result in the message control would look like this:"5,600.44".

Code Block
languagejavascript
var x, x1, x2;
if (Num.value > 0) {
    var nStr = Num.value.toFixed(2);
    nStr += '';
    x = nStr.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
 x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    Message.value = x1 + x2;
}

Textarea Max Length

In html there is no way to set a maxLength on a textarea control. This is why the textarea control does not have a maxlength property like the text control does. It is possible to do this via a business rule. This example form has a textarea control named 'Desc' where the user can enter up to a 500 character description. On this control we also set the ErrorMsg property to the string 'You must limit your description to 500 characters'. This message is automatically displayed when the description control is set to invalid by the following business rule.

Code Block
if (Desc.value.length > 500) {
  Desc.valid = false;
} else {
  Desc.valid = true;
}

You can even customize the error message by adding this line to your rule. Now the error message will tell the user how many characters they are over the maximum allowed.

Code Block
Desc.status = 'Invalid. Max 20 chars allowed and you have ' + Desc.value.length; 

Textarea newline vs break

Users typically enter multi-line text into textarea controls. If you want to display that text in an html context, for example on a web page or in an html formatted email or in your form's Form Action display message you will need to replace newlines with html breaks. This caused by the fact that line breaks entered into a web form textarea are represented by a single newline character \n while line breaks in an html context are represented by the html break characters.

Our example has a textarea control named Description and a hidden control named DF. The user types into the visible control named Description and a business rules converts the newline characters \n into html breaks.

Code Block
languagejavascript
var x = Description.value; 
x = x.replace(/\\r/g,"");
x = x.replace(/\\n/g,"<br/>"); DF.value = x;

Dropdown Options

This example automatically sets the option selected in one dropdown based on the option selected in another. This is often useful when you have a form with choices that were dynamically populated. For example, imagine product choices which are descriptive text. When the user selects a product, your form needs to perform an action based on a product ID rather than the descriptive product text. A nice way to do this is to have the rule that dynamically populates the product choices dropdown also populate a product ID dropdown which remains an invisible control in the form. The product choices dropdown control was named Products and the product ID dropdown control was named PID

The 1st rule "Load Products" populates both the visible and hidden dropdowns with options from a database.

Code Block
/*member productCode, productName, resultSet*/
var x;
  
if (form.load) {
  eval('x=' + http.get('https://app.frevvo.com/database/BIRT/allProducts'));  
 
    var opts1 = [];
    var opts2 = [];
 
    for (var i=0; i < x.resultSet.length; i++) {
        if (Products.value === Products.options[xx.resultSet[i]) {
            opts1[i] = Products.options.indexOf(Products.options[x])x.resultSet[i].productName;
 }   PID.value        opts2[i] = PIDx.optionsresultSet[i] + ''; 
}

In v4 rules using hidden dropdowns to keep descriptive option labels visible to the user while keeping cryptic database values hidden are often no longer necessary. Dropdown options have values distinct from the human visible option labels. The above can now be achieved with a single simpler rule:

Code Block
/*member description productId resultSet */
var x, opts1;
 
for (var i=0; i < x.resultSet.length; i++) { 
    if (x.resultSet[i]) { 
            opts1[i] = x.resultSet[i].productId+ '=' + x.resultSet[i].description.productCode;
        }
    }
 
  Products.options = opts1;
  PID.options = opts2;
  Products.value = opts1[0]; // default to 1st product option
  PID.value = opts2[0];
}

Finding a Selected Options Index

The 2nd rule Select Product ID keeps the hidden PID dropdown syncronized with the visible Products dropdown.

Code Block
languagejavascript
if (Products.value.length > 0)
{
    var i;
    for }(var x }in 
RdocnumProducts.options) = opts1; 

Here is another rule that dynamically populates both the product choices and product ID dropdowns. This rule calls a REST Service which returns an object rather than the resultset returned by the database connector as shown above. See the section on dynamic content for more details. 

Code Block
/*member ids products */
var x;{
        if ((SProducts.value.length > 0) {
    eval('x=' + http.get('http://localhost:8182/products/?category=' + S.value)); 
    P.options = x.products; + '=' + Products.value) === Products.options[x]){
            i = Products.options.indexOf(Products.options[x]);
        }
    }
 
  IDPID.optionsvalue = x.idsPID.options[i].split('=')[0];

}

Synchronized Selects

The Product Search example above is often used in conjunction with a hidden select control. Imagine that your database table contains a list of products. Each product has product description also a unique product ID. The user needs to select a product from a dropdown on your form. You want to populate the dropdown with the product descriptions. The users do not need to see or know the product IDs but you need to use the ID as the key into the database for other selects. To do this add another hidden dropdown to the form and populate it with the IDs. This example has a visible dropdown name Products and an invisible dropdown named PID. See the rule above that populates these dropdowns dynamically from the database.

This rule below keeps the PID selected option in sync with the selected Product.

Code Block
var i, x; 
for (x in Products.options) { 
// Determine the index of the selected product in the Products dropdown options 
if (Products.value === Products.options[x]) 
    i = Products.options.indexOf(Products.options[x]); 
}

 
// Changed the selected PID to match the selected Product 
PID.value = PID.options[i] + '';

Clearing Dropdown Options

This sample resets a dropdown option to the automatically added blank option. For dropdowns added from palette controls and from schema,  automatically adds a blank option so the dropdown initially shows no choice by default. To reset the dropdown, set the dropdown control's value to null not the empty string. The empty string will not work since the empty string is not a valid option. This form resets the dropdown named size whenever the value of the product option changes.

Code Block
if (product}

In v4 rules using hidden dropdowns to keep descriptive option labels visible to the user while keeping cryptic database values hidden are often no longer necessary. Dropdown options have values distinct from the human visible option labels. The above can now be achieved with a single simpler rule:

Code Block
/*member description productId resultSet */
var x, opts1;
 
for (var i=0; i < x.resultSet.length; i++) { 
    if (x.resultSet[i]) { 
            opts1[i] = x.resultSet[i].productId+ '=' + x.resultSet[i].description; 
    } 
} 
Rdocnum.options = opts1; 

Here is another rule that dynamically populates both the product choices and product ID dropdowns. This rule calls a REST Service which returns an object rather than the resultset returned by the database connector as shown above. See the section on dynamic content for more details. 

Code Block
/*member ids products */
var x;
 
if (S.value.length > 0) {
    eval('x=' + http.get('http://localhost:8182/products/?category=' + sizeS.value)); 
    P.options = null; 
}

Default Option

When your options are set dynamically as shown below in a business rule, you cannot set a default in on the form designer. You need to set the default in the rule. If your options have <value>=<label> where value is different from label, make sure you set the <control>.value to <value> not <label> and not <value>=<label>

Code Block
if (form.load) { 
    var cc = ['R=Red', 'B=Blue', 'G=Green'];
    Colors.options = cc;
    Colors.value = 'B';
}

Checkbox Options - Assigning Color to Checkbox Choices

Checkbox controls are different from all other  palette controls in that they are multi-select. Therefore the way to write rules with checkbox controls are in many ways similar to rules with repeat controls. This rule has a checkbox controls with name colorPalette with the options: purple, green, blue, yellow, orange. The form also contains a text control with name colorChoice. This rule assigns colorChoice the choices selected from colorPalette.

Code Block
var choices = ''; 
for (var i = 0; i < colorPalette.value.length; i++) 
{  
    choices = choices + colorPalette[i].value; 
} 
colorChoice.value = choices; 

Notice that similar to repeat controls, due to an internal evaluation limitation, you must collect the choices in a variable inside the for loop. And then assign that control Name.value to that variable outside the for loop.

This rule is another example showing how checkbox controls are array types.

Code Block
if (colorPalette.value.length > 0) 
{ 
    colorChoice.value = 'Thank you x.products; 
    ID.options = x.ids; 
}

Synchronized Selects

The Product Search example above is often used in conjunction with a hidden select control. Imagine that your database table contains a list of products. Each product has product description also a unique product ID. The user needs to select a product from a dropdown on your form. You want to populate the dropdown with the product descriptions. The users do not need to see or know the product IDs but you need to use the ID as the key into the database for other selects. To do this add another hidden dropdown to the form and populate it with the IDs. This example has a visible dropdown name Products and an invisible dropdown named PID. See the rule above that populates these dropdowns dynamically from the database.

This rule below keeps the PID selected option in sync with the selected Product.

Code Block
var i, x; 
for (x in Products.options) { 
// Determine the index of the selected product in the Products dropdown options 
if (Products.value === Products.options[x]) 
    i = Products.options.indexOf(Products.options[x]); 
}

 
// Changed the selected PID to match the selected Product 
PID.value = PID.options[i] + '';

Clearing Dropdown Options

This sample resets a dropdown option to the automatically added blank option. For dropdowns added from palette controls and from schema,  automatically adds a blank option so the dropdown initially shows no choice by default. To reset the dropdown, set the dropdown control's value to null not the empty string. The empty string will not work since the empty string is not a valid option. This form resets the dropdown named size whenever the value of the product option changes.

Code Block
if (product.value.length > 0) {  
    size.value = null; 
}

Default Option

When your options are set dynamically as shown below in a business rule, you cannot set a default in on the form designer. You need to set the default in the rule. If your options have <value>=<label> where value is different from label, make sure you set the <control>.value to <value> not <label> and not <value>=<label>

Code Block
if (form.load) { 
    var cc = ['R=Red', 'B=Blue', 'G=Green'];
    Colors.options = cc;
    Colors.value = 'B';
}

Checkbox Options - Assigning Color to Checkbox Choices

Checkbox controls are different from all other  palette controls in that they are multi-select. Therefore the way to write rules with checkbox controls are in many ways similar to rules with repeat controls. This rule has a checkbox controls with name colorPalette with the options: purple, green, blue, yellow, orange. The form also contains a text control with name colorChoice. This rule assigns colorChoice the choices selected from colorPalette.

Code Block
var choices = ''; 
for (var i = 0; i < colorPalette.value.length; i++) 
{  
    choices = choices + colorPalette[i].value; 
} 
colorChoice.value = choices; 

Notice that similar to repeat controls, due to an internal evaluation limitation, you must collect the choices in a variable inside the for loop. And then assign that control Name.value to that variable outside the for loop.

This rule is another example showing how checkbox controls are array types.

Code Block
if (colorPalette.value.length > 0) 
{ 
    colorChoice.value = 'Thank you for choosing colors'; 
} 
else 
{ 
    colorChoice.value = 'Please choose colors...'; 
}

...

Info

Avoid using message controls, images & video controls inside a section that contains other controls that you may want to make invisible. Since a these three control types always contains a value, it can cause a section, or other controls in a section, to become required, and this can disable the form's Submit button. If you must include these controls, place them outside the section. Another alternative is to write rules for the individual controls within a section to set them to visible/invisible or required/not required

...

Warning

Rules initializing dates & time will not work in a form.load rule unless you specify a timezone on the form's Url via the _formTz Url parameter. This is because the form server needs to know the timezone in which to return the date and time. If you do not specify a _formTz the methods will return null and the control values will remain blank. The timezone strings can be found here. For example, to specify Eastern time: &_formTz=America/NewYork.blank. The timezone strings can be found here. For example, to specify Eastern time: &_formTz=America/NewYork.

Age

This example form automatically determines today's date and then calculates the person's age in the control named 'Age' when they enter their birth date into the control named 'BirthDate'.

Image Added

Code Block
languagejavascript
if (BirthDate.value.length > 0) {
  var today = new Date();
  var dob = BirthDate.value.split('-'); 
  var dob2 = new Date(dob[0],dob[1]-1,dob[2]);
  var age = today.getFullYear() - dob2.getFullYear();
  if (today.getMonth() < dob2.getMonth() || 
     (today.getMonth() === dob2.getMonth() &&
      today.getDate() < dob2.getDate())) {
    age -= 1;
  }
  if (age >= 0) {
     Age.value = age;
  } else {
     Age.value = null;
  }
}
 

Duration

This form initializes the hospital discharge date using a rule, and when the user enters the admission date a 2nd rule calculates the number of days the patient stayed in the hospital.

...

Code Block
/ Calculate Hospital Stay Duration 
if (A.value !== '' && D.value !== '') { 
    var da = A.value.split('-'); 
    var Ams = new Date(da[0],da[1],da[2]); 
    da = D.value.split('-'); 
    var Dms = new Date(da[0],da[1],da[2]);
 
    if (Ams > Dms) { 
        Days.value = 'Discharge date must be after Admission Date'; 
    } else { 
        Days.value = (Dms - Ams) / (1000*60*60*24) + ' days'; 
    } 
}

 

Duration Between Date and Time

Here is a rule example to calculate the time difference between two Date/Time values in hours:minutes format :  

...

One special consideration for tables is that rules which dynamically set the column header label, hint and help mesages must use the array syntax. This is somewhat counter-intuitive since each column appears to have only a single label, help and hint. Here is the rule to dynamically set these three properties: 

Code Block
FirstName[0].label = 'blah label';
FirstName[0].hint = 'blah hint';
FirstName[0].help = 'blah help';

Clearing Values in a Table

This rule clears the values from all rows in a table. Notice the For loop that iterates over all the rows. Inside the loop a null value is assigned to all the columns in the table row.

FirstName[0].label = 'blah label'; FirstName[0].hint = 'blah hint'; FirstName[0].help = 'blah help';
Code Block
languagejs
for (var i = 0; i < Col0.value.length; i++) { 
    Col0[i].value = null;
    Col1[i].value = null;
    Col2[i].value = null;
  } 

You cannot clear an entire table from a rule.

Note

A section in a repeat will behave differently than a table row when using a rule to set the valid property. For Example, drag and drop a table control into your form. Name it T. Then drag and drop a section into the same form. Name it S. Add a control to the section. Name the control C. Drop the section into a repeat named R. Add this rule to the form.

Code Block
if(form.load){
 S[0].valid = false;
 TItem[0].valid = false;
}

The section header shows "Invalid value" as a message while the table row shows no such indication signifying an invalid row.

...

Code Block
if (form.load) { 
    if (_data.getParameter('flow.activity.name') === 'Manager Review') { 
Review.visible = true; 
    } 
} 

 

form.unload

Rules can be used to finalize field values after the users clicks the form's submit button but prior to the Form and Doc Action execution. Rules using form.unload are triggered when the form user clicks the submit button and for workflows when the user clicks continue to go to the next activity or finish to complete the flow.

...

A rule can dynamically display an image uploaded to your form via the upload control. In this example the upload control is named 'u'. The form also must contain a message control as a place holder for displaying the uploaded image. The rule dynamically creates a URL to the uploaded image in the temporary attachment repository. The upload control's value 'u.value' is a GUID that uniquely identifies the attachment. The uploaded image is included in the submissions pdf.

Code Block
languagejavascript
if (u.value.length > 0) {
  var baseUrl = _data.getParameter('_frevvo_base_url') + 
      "/frevvo/web/tn/" +
      _data.getParameter('tn.id') +
      "/user/"+_data.getParameter('user.id') +
      "/app/"+_data.getParameter('app.id') +
      "/form/"+_data.getParameter('form.id');
 
  im.value = "'<img src="'" +
         baseUrl + "'/attachment/"' + u.value+"'/does_not_matter'"/>"';
} 

Here is the example form before and after the user has uploaded the orangegrove.png image:

...