Section | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
...
Many times the condition name.value.length > 0 can be dropped altogether and the rule can be simplified. This rule executes whenever a user enters a value into either the control named firstname or lastname because the firstname and lastname controls are on the left-hand side (LHS) right side of the assignment operator.
...
- visible : Set to false to hide a control and true to make the control visible.
- value : Read or write the value of a control. This is not applicable to sections, tabs and other controls where it does not make sense to set a value.
- enabled : Set to false to disable (grey out) a control so that a user can not change its value and true to enable it. This is not applicable to sections, tabs and other controls that do not make sense to disable/enable.
- expanded : Set to false to collapse a group control (sections controls only) and true to expand a group control.
- selected : Set to true to make a tab the selected tab (tab controls only).
- valid : The value of this property is true if the control contains a valid value otherwise false. Validity is based on the control’s type. For instance a numeric control will be invalid if the user enters a string value that cannot be converted to a number. This property can be read as well as written.
- required : Set to true to make a control required and display a yellow background color. (NOTE: only affects palette controls and not controls generated from XSD schema data source). This is also a property of section controls. Setting a section required to false automatically sets all inner controls to not required.
- options : This property enables dynamic setting select control options (radio, dropdown & checkbox controls only).
- label : This property sets the label seen on any control including sections.
- help : This property sets the help text.
- hint : This property sets the hint seen on hover.
- status : This property sets the error message display whenever the control's value is invalid. The one exception is the Required Property for Controls in an Accessible form/flow .
- clicked : This property works with trigger controls. Its initial state is false. When a user clicks a trigger its state turns true.
- printable: Set to false to remove the control from both the printable view and PDF submission document.
- itemAdded : This property works with repeat controls. Its initial state is false. When a user clicks "+" to add a repeat item AND when a repeat item is added via a Document URI as the form loads its state turns true.
- itemRemoved : This property works with repeat controls. Its initial state is false. When a user clicks "-" to delete a repeat item its state turns true.
- itemIndex : This property works with repeat controls. When an itemAdded or itemRemoved event fires the value of itemIndex is set. For itemRemoved events itemIndex will return -1. For itemAdded events itemIndex will give you the index of the added item
These two three special identifiers do not reference a specific control name. They use the static name "form". See Rule Examples for many use cases with these identifiers.
- form.load : This property is true when the form is first loading. It is useful for setting default values via rules that you need to be set before the user starts interacting with the form. This also holds true for flows. This property is true when each step of a workflow is first loading.
- form.unload : This property is true when users click the form's submit button. It is useful for setting control values just prior to the execution of the form's Doc Actions and Form Actions. This also holds true for flows. This property is true when the user clicks the continue button for each workflow step. Refer to this topic for the details about a change in behavior that has been implemented for Forms only.
- form.positionUpdated : This property is used for the Geo location feature. You can fire a rule using this special identifier every time the position is updated.
- Activate : Use this property instead of form.load to prevent invalid flow states when navigating back and forth in a workflow.
- Deactivate: Use this property instead of form.unload to prevent invalid flow states when navigating back and forth in a workflow.
Examples of identifiers used in rules are:
...
- Browser independence. We found it impossible to get these to run reliably in so many versions of so many browsers, especially IE. A bug in your rule (e.g. an infinite loop) will crash the browser and in some cases will require a Windows reboot. On the server, these run in separate threads with lower priority and timeouts so it will not impact the form server.
- The ability for the rule to do server-side things like http:get () to a database connector, invoke a REST service etc. These often reside behind the firewall and are not accessible to the browser.
- The rules are not exposed to the browser at all so any sensitive information in the rule (e.g. a password) won’t leave the server. However, we do not recommend putting any sensitive information in a rule.
- Rules can use information like the currently authenticated subject user id, name, email etc. though technically it would be possible to make this available on the browser if required. However, providing this information in the browser is a potential security hole.
- Rules can also modify a control – in theory, this can cause large-scale changes to the form’s valid state. Think of an optional XML complex type that has a deeply nested data structure inside it with some required and some optional elements. If any element has a value, all the other required elements become required. It’s much easier and efficient to analyze the form on the server although, technically, this is also possible in the browser. It can be extremely slow for large forms, especially in IE or if someone is running on a slower machine.
These pros of excuting rules server-side mitigate the couple cons:
...
There is a potential for performance bottlenecks. However, this is rare since rules are not compute intensive typically. We think the benefits outweigh the drawbacks here.
Dates and Times
There are several special considerations when writing rules using date, time and date/time controls. You can also find many working samples in the Rules Examples chapter.
...
The validator also supports global directives. Use the global directive to identify additional global objects and functions defined in the execution environment and made available to the rule for which it is not appropriate to include a var statement in the rule code itself. One directive can be used to list all additional globals on a single line. Currently there are no known cases requiring the use of the global directive.
Rule Editor Functions
The Rule Validator includes an enhanced editor designed to provide an easy experience when developing rules.The rule editor box includes the following features:
Features | Description |
---|---|
Line Numbers | Line numbers in the rule code editor make it easier to correlate reported validation errors with the line of code. |
Bracket auto close | Type a {, ( or [ and the closing bracket is automatically inserted. |
Match Bracket | Place the cursor on a bracket and both it and the matching bracket are shown in a matching distinctive color (green). |
Syntax Hi-lighting | JavaScript syntax hi-lighting with keywords, variables, comments, etc. shown in distinctive colors. |
Auto Indent | New lines are auto-indented according to generally accepted code formatting rules. |
Code Folding | Bracketed code blocks (functions, if-then-else blocks, etc.) are collapsible. Click the arrow immediately to the right of the line numbers to collapse/expand code blocks. |
Full screen edit mode | Expand the editor to full screen mode if you need more space to work. Click the "double arrow" expand icon (directly above the editor box) or press F2 when your cursor is inside the Rule box to expand to full screen. The ESC key returns you to small window mode. |
Auto Complete/Hinting | When composing a rule, the designer can pick from a list of available controls and their properties directly within the rule editor. The pick list is context sensitive and will behave differently based on where the cursor is located when it is invoked. When on a blank space or immediately following an open bracket/brace, it can be manually invoked using Ctrl-Space to bring up a list of controls. Typing a dot (.) immediately after a control name or after the index ("[i]") that follows a control name will automatically bring up a context sensitive pick list of properties applicable to that control for selection. You can type the first letter of the item you are looking for and the property starting with that character will be highlighted in the list. Continue typing and the matching options will progressively narrow to the characters typed. Double click your choice using the mouse or press the Enter key to select an item. Any other key dismisses the pick list. . See the example below. |
Help | The help icon displays a small help window listing the hot keys described above - (F2, ESC and Ctrl-Space) |
...
- START - signals the start of an execution that may span one or more rules and Doc URIs
- END - signals the end of the execution of a batch of one or more rules plus the total execution time in milliseconds
- ERROR - any errors that were thrown NOT in the context of executing rules
- START_RULE - signals the start of a rule execution
- END_RULE - signals the end of a rule execution plus the execution time of this one rule in milliseconds
- RULE_ERROR - any errors that happened while executing the specific rule
- RULE_EVAL - A message displaying the rule script
- RULE_DEP - one for each rule dependency. Examples of dependencies are: form.load, trigger clicked, if conditions that trigger rules, control values changes on the right hand side of assignments, etc..
- RULE_SCHEDULE - shows the next rule to execute and the remaining rules in the agenda/batch. This event makes it a bit easier to track what the rules engine is doing when debugging.
- PROPERTY_SET - one for each control property set by the current rule
- HTTP_START - signals the start of an http call (get, put, ...)
- HTTP_END - signals the end of the http call + status code and timing
- HTTP_RESPONSE - a message that dumps the first few lines of the http response
- HTTP_ERROR - any errors that may have been thrown while performing the http call
- DOC_READ_START - signals the start of a manually set Doc URI read
- DOC_READ_END - signals the end of a manually set Doc URI read
- DOC_READ - signals the success or failure of the Doc URI read
- LOG - a user defined message that can be generated from a rule using frevvo.log('my INFO message') or frevvo.log('DEBUG', 'my debug message')
- INFO - this statement informs the designer when the set of property values in a flow during form state initialization are ignored.
...
To set the timeout to 15 seconds set value="15000"
Rule Execution Priority
This experimental features lets you control the order of execution in complex rules usage. There is no UI for this feature. Please contact customer support for information.
An example usage: Rule1 is called when multiple form field values change. Rule2 has many XXX.value = ... that would trigger Rule1. If the rules engine happens to always picks Rule2 to execute first, you would execute Rule1 more than is needed. While rule ordering doesn't cause a behavior issue, if Rule1 happens to perform a more time consuming operation such as retrieving data from a database, this may cause a performance issue. Rule execution priority enables you to tell the rules engine to execute Rule1 before Rule2. Then each subsequent call to Rule1 would be prevented.
Rules and Repeating Controls
If you have a repeating control in a form that itself contains a repeating control, you cannot apply a 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.
Dynamic Add or Remove for Repeating Items
The minOccurs and maxOccurs (Max#) properties of a Table or Repeat control, can be used to write a rule to dynamically change Min# and Max# values of repeating items. Here's how it works:
In the designer, set the min/max properties so that they cover the whole range of min and max numbers that you wish to use via rules. When you increase the Min# value with a rule, will check if that number of items are there in form, if not then it will add them. When you reduce the Max# via rule, will check if the form has more than that many number of items. If there are more items than the Max# that you are setting via rule, it will remove those extra items.
This is a way to dynamically change the min and max properties set for these controls in the designer. This feature is helpful if you want to allow only a certain number of items based on user input.
Follow these important points when writing your rule:
...
Your rule can set minOccurs to 0 even if the design time setting > 0, but you cannot set minOccurs to a value which is greater than the current maxOccurs.
...
Your rule can set maxOccurs to a value that exceeds the design time setting, but you cannot set maxOccurs to a value below the current minOccurs value.
...
Repeat items and table rows are added if your rule increases the Min# property and are removed when the rule decreases the Max#.
...
Rules and Repeating Controls
If you have a repeating control in a form that itself contains a repeating control, you cannot apply a 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.
Dynamic Add or Remove for Repeating Items
The minOccurs and maxOccurs (Max#) properties of a Table or Repeat control, can be used to write a rule to dynamically change Min# and Max# values of repeating items. Here's how it works:
In the designer, set the min/max properties so that they cover the whole range of min and max numbers that you wish to use via rules. When you increase the Min# value with a rule, will check if that number of items are there in form, if not then it will add them. When you reduce the Max# via rule, will check if the form has more than that many number of items. If there are more items than the Max# that you are setting via rule, it will remove those extra items.
This is a way to dynamically change the min and max properties set for these controls in the designer. This feature is helpful if you want to allow only a certain number of items based on user input.
Follow these important points when writing your rule:
Your rule can set minOccurs to 0 even if the design time setting > 0, but you cannot set minOccurs to a value which is greater than the current maxOccurs.
Your rule can set maxOccurs to a value that exceeds the design time setting, but you cannot set maxOccurs to a value below the current minOccurs value.
Repeat items and table rows are added if your rule increases the Min# property and are removed when the rule decreases the Max#.
Added rows due to increase in Min# will trigger the itemAdded property.
This feature can be used for schema controls, but min/maxOccurs values have to be set within the limit given in the schema. For example, if the schema has text control defined with minOccurs=2 and maxOccurs=100. We cannot set minOccurs less than 2 and max greater than 100.
A common example is a form that retrieves data from a database - let's say the details of a Purchase Order. There could be 1 or more rows in the result. Depending on how many rows are returned, you may want to show only those many repeats/table rows in the users form. Your rule can automatically set the min and max properties of the repeat/table to a same value (Min# = Max#) so that only the number of items specified in your rule display.
Refer to this example.
What is not permitted in a rule?
...
Business rules can interact with web services to retrieve data from back end systems and to update/insert data into back end systems using the http.get(), http.put(), http.post() and http.delete() methods.
There These are three the parameters to an these http postmethods:
- the URL to the web service
- payload (data) constructed as a JavaScript object.
- headers constructed as a javaScript JavaScript object
The advantages to this approach are:
- the rule will fail when executed if the object syntax is incorrect
- takes care of encoding to JSON automatically.
In previous versions of , the post, put, |get, |delete} methods accepted only a string object for payload and header parameters. To use native javascript objects, the designer would have to use JSON.stringify({name:Name.value}) to make it work.
Code Block |
---|
public String get (String url)
public String get (String url, String headers)
public String post (String url)
public String post (String url, String payload)
public String post (String url, String payload, String headers)
public String post (String url, String payload, String headers, boolean multipart)
public String put (String url) {
public String put (String url, String payload)
public String put (String url, String payload, String headers)
public String put (String url, String payload, String headers, boolean multipart)
public String delete (String url)
public String delete (String url, String headers |
...
- Whether the payload is in multipart form
In previous versions of , the post, put, get and delete methods accepted only a JSON string for payload and header parameters. Using string concatenation to generate a JSON string is fragile due to potential encoding issues and possibly XSS security concerns. This requires the designer to use JSON.stringify('{name:'+Name.value+'}')) to avoid encoding issues.
Code Block | ||
---|---|---|
| ||
/**
Performs an HTTP GET
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@return {String} - the target resource (e.g. {"CustomerName":"John Doe"})
*/
function get (url){...}
/**
Performs an HTTP GET with headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@param {Object} headers - request headers" (e.g. {"X-MyHeader":"MyHeaderValue"})
@return {String} - the response (e.g. {"CustomerName":"John Doe"})
*/
function get (url, headers){...}
/**
Performs an HTTP POST
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@return {String} - the response (e.g. {"CustomerName":"John Doe"})
*/
function post (url){...}
/**
Performs an HTTP POST with a payload
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@param {Object} payload - the POST request payload
@return {String} - the response (e.g. {"CustomerName":"John Doe"})
*/
function post (url, payload){...}
/**
Performs an HTTP POST with a payload and headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@param {Object} payload - the POST request payload
@param {Object} headers - request headers" (e.g. {"X-MyHeader":"MyHeaderValue"})
@return {String} - the response (e.g. {"CustomerName":"John Doe"})
*/
function post (url, payload, headers){...}
/**
Performs an HTTP POST with a payload and headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@param {Object} payload - the POST request payload
@param {Object} headers - request headers" (e.g. {"X-MyHeader":"MyHeaderValue"})
@param {Boolean} multipart - is the request payload multipart?
@return {String} - the response (e.g. {"CustomerName":"John Doe"})
*/
function post (url, payload, headers, multipart){...}
/**
Performs an HTTP POST with a payload and headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@return {String} - the response (e.g. {"CustomerName":"John Doe"})
*/
function put (url){...}
/**
Performs an HTTP POST with a payload and headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@param {Object} payload - the POST request payload
@return {String} - the response (e.g. {"CustomerName":"John Doe"})
*/
function put (url, payload){...}
/**
Performs an HTTP POST with a payload and headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@param {Object} payload - the POST request payload
@param {Object} headers - request headers" (e.g. {"X-MyHeader":"MyHeaderValue"})
@return {String} - the target resource (e.g. {"CustomerName":"John Doe"})
*/
function put (url, payload, headers){...}
/**
Performs an HTTP POST with a payload and headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@param {Object} payload - the POST request payload
@param {Object} headers - request headers" (e.g. {"X-MyHeader":"MyHeaderValue"})
@param {Boolean} multipart - is the request payload multipart?
@return {String} - the target resource (e.g. {"CustomerName":"John Doe"})
*/
function put (url, payload, headers, multipart){...}
/**
Performs an HTTP POST with a payload and headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@return {String} - the target resource (e.g. {"CustomerName":"John Doe"})
*/
function delete (url){...}
/**
Performs an HTTP POST with a payload and headers
@param {String} url - the target resource url (e.g. "http://myservice/myresource")
@param {Object} headers - request headers" (e.g. {"X-MyHeader":"MyHeaderValue"})
@return {String} - the target resource (e.g. {"CustomerName":"John Doe"})
*/
function delete (url, headers){...} |
The http.get(), http.post(), http.delete() and http.put() methods now accept the payload and headers as native JavaScript object directly eliminating the need for the JSON.stringify() function. This is the preferred way of sending payload and headers from rules.
...
Code Block |
---|
http.get('http://localhost/my/service', JSON.stringify('{name: '+Name.value+'}')); |
Use the preferred methoda native JavaScript object:
Code Block |
---|
http.get('http://localhost/my/service', {name: Name.value}); |
Here is another example. The image shows a section of a business rule used to read from a Google sheet. Notice Sample 2 (Headers as a JavaScript object) does not include the single quotes present in the first sample (Headers as a string). Although both methods will work, Sample 2 shows the preferred method:
the preferred method:
The advantages to this approach are:
- the rule will fail when executed if the object syntax is incorrect
- takes care of encoding to JSON automatically.
Dynamic Content
Real business forms often require dynamic content in dropdown list. Often based on the value entered into one form field, the values in other fields or options available in select controls need to be dynamic.
...
You can use a form.load 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, Roles and RolesManager, the following rule will prefill those fields as indicated below.
Code Block |
---|
if (form.load) { // User Information Id.value = _data.getParameter('subject.id'); // Username FirstName.value = _data.getParameter('subject.first.name'); LastName.value = _data.getParameter('subject.last.name'); Email.value = _data.getParameter('subject.email'); Manager.value = _data.getParameter("subject.reports.to"); var roles = _data.getParameter ("subject.roles"); if (roles) { eval ('x=' + roles); Roles.options = x; } } |
This rule is useful in a workflow where you want to make a the tab named Review visible only for the workflow activity named Manager Review.
Code Block |
---|
if (form.load) { if (_data.getParameter('flow.activity.name') === 'Manager Review') {); ReviewRoles.visibleoptions = truex; } } |
Security Subject Information from LDAP
LDAP supports both the standard subject attributes and custom attributes. When a user is successfully authenticated by the LDAP security manager, Live Forms automatically retrieves Last Name, First Name and Email Address for this user from the LDAP server. You can retrieve custom attributes in addition to the standard ones from Active Directory and pull the data into your form/flow using business rules.
...
You can retrieve additional custom attribute information from the LDAP server by listing the custom attributes in a separated list in the custom field on the LDAP Configuration screen. Then write a rule to use that information in your form. For example, this rule populates the Middle Initial and Home Phone fields which are retrieved from the LDAP server by configuring custom attributes.
Code Block |
---|
if (form.load) { FirstName.value=_data.getParameter('subject.first.name'); MiddleInitials.value=_data.getParameter('subject.initials'); LastName.value=_data.getParameter('subject.last.name'); HomePhone.value=_data.getParameter('subject.telephoneNumber'); EmployeeEmail.value=_data.getParameter('subject.email'); } |
...
Attributes with more than one value are also supported. For example, The carLicense attribute can return multiple licenses. You can write a rule to populate dropdown options with those values. Make sure the carLicense attribute is added to the custom field on the LDAP Configuration screen and of course, there are multiple carLicense attributes, each one containing a different value for the dropdown options, set up for appropriate users on the LDAP server.A JSON array string listing multiple car licenses is returned and it can be used in a rule to populate the options of a dropdown control named carLicense. for appropriate users on the LDAP server.
A JSON array string listing multiple car licenses is returned and it can be used in a rule to populate the options of a dropdown control named carLicense.
Code Block |
---|
if (form.load) {
carLicense.options=JSON.parse(_data.getParameter('subject.carLicense'));
} |
Note |
---|
The manager attribute maps to the built-in data - subject.reports. to. This means you can retrieve this value in a rule or use subject.reports.to for flow navigation if you configure the manager attribute in your LDAP tenant. |
Execute a Rule on a Specified Workflow Step.
Using the flow.activity.name built-in parameter in a rule ensures that the actions in the rule only occur when the workflow is on a specified step. Here is an example of a rule that makes a tab named Review visible only for the workflow step named Manager Review.See this topic for more information.
Code Block |
---|
if (form.load) { carLicense.options=JSON.parse if (_data.getParameter('subject.carLicense')); } |
Note |
---|
The manager attribute maps to the built-in data - subject.reports. to. This means you can retrieve this value in a rule or use subject.reports.to for flow navigation if you configure the manager attribute in your LDAP tenant.'flow.activity.name') === 'Manager Review') {
Review.visible = true;
}
} |
Built-in Methods
provides built-in helper methods for common functionality required by business rules.
...
- Time - frevvo.currentTime() - returns the current time in the user's local timezone. This method should only be used to set the value of a Time control.
- Date - frevvo.currentDate() - returns the current date in the user's local timezone. This method should only be used to set the value of a Date control.
- DateTime - frevvo.currentDateTime() - returns the current date and time in the user's local timezone. This method should only be used to set the value of a Date/Time control.
- String DateUtil.TodaytodayISO() - returns today's date in 'yyyy-mm/-dd/yyyy format' format. The date is returned in the server's timezone.
- frevvo.beforeDate(Date1.Date2): true if Date2 is earlier than Date1.
- frevvo.afterDate(Date1, Date2.value): true if Date2 is after Date1. Date1 and Date2 are controls in your form. You can also write a rule to add .
- frevvo.addToDate(date, "m, d, or y", "number of days, months or years you want to add") - Add a number of years,days or months to a date. See an example here.
...
Code Block |
---|
Tm.value = frevvo.currentTime(); Dt.value = frevvo.currentDate(); DtTm.value = frevvo.currentDateTime(); |
The methods listed below have been deprecated and will be removed in a future release.
- frevvo.currentTime(form);
- frevvo.currentDate(form);
- frevvo.currentDateTime(form);
- String DateUtil.today()
If these methods are used in rules a the designer will see a message in the Debug Console urging that the methods listed above be used instead.
...
There is one method that will access the current locale in a rule. For example, if you wanted to generate PDFs for different languages, you can use this method will take the value of the locale from the URL. You can then write a rule or, in the case of PDFs, a precondition to set up selection criteria.
...
Click the View All button to display all the rules in your form/flow. Then use a browser search (Ctrl+F) to highlight all the places in your rules where a particular search item is mentioned. For example, if you were looking for all the rules that set the required property for a section, search for 'SectionName.required' (replace SectionName with the name of your section ) . This view might be helpful when correcting errors reported by the Rules Editor.
...