V4 Business Rules
From Frevvodocs
Rules
Overview
Rules add behavior to forms. For instance, you can add a frevvo rule that will show/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 forms. Rules can also be used to update form values. For instance, you can compute the total invoice price on an order form from values of other form fields such as item quantity and price.
Working with Rules
In the form designer, click on the Rules tab. The page will display any existing rules that you may have created for this form.
You may create a new rule by clicking on the
icon. Your new rule is given a randomly generated name. You can edit the name as described below.
Each rule has three icons. Each is described below.
- Click the
icon to edit an existing rule. You can edit the name, description and statement (JavaScript code) for the rule.
- Click the
icon to delete a rule. Confirm your choice in the dialog that pops up and the rule will be immediately removed. This is an irreversible process so make sure you do not need the rule before you delete it.
Rules can be temporarily disabled by unchecking the enabled' checkbox. Edit the rule and scroll down below the rule code.
Writing Rules
In this version of frevvo, a rule is created as a piece of JavaScript code. A future version of frevvo will provide a Rules wizard that makes it easier to create rules in a visual manner. Rules are saved and runable after you commit your form. In order to test a rule you must first commit your form. Then test it in use mode by clicking on the
icon.
A rule is of the form:
if (condition)
{
true actions;
}
else
{
false actions;
}
You can create more advanced rules primarily for the purpose of looping over repeating items. We will describe these later.
Rules do not currently support the syntax:
- if (condition) statement1 else if (condition) statement2
- switch statement
Writing Conditions
One of the most common conditions is a rule that executes as soon as the user enters a value in 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 rule can be simplified. This rule executes whenever a user enters a value into either the control named firstname or lastname.
fullname.value = firstname.value + ' ' + lastname.value;
Rules Wizard
Future frevvo releases will support a rule wizard making it easier to create rules without needing to understand simple JavaScript expressions and making it quicker to reference controls without needing to first assign them a unique ID. Also at this time rules support a single condition, true action and false action. Future frevvo releases will support multiple conditions and actions.
Control Name
Rules usually need to reference form controls. This is accomplished by assigning each control a unique Name. The edit container for each control has a Name field. You may enter any string as the Name.
All control instances will have the same name. This is important for repeating controls. Let's say you have a repeating control 'Email Address' and you assign it a Name of Email. If the user wishes to enter three email addresses and creates three instances of the repeating 'Email Address' control, all three instances will have the same Name (Email). The rule must reference these repeating items as an array. We will describe repeating items in more detail below.
NOTE: It is very important when using a control in a rule that the control has a unique name. If multiple controls have the same name frevvo can not determine which control the rule refers to. Controls added to your form from palette are for the most part forced to have a unique name. If you try to change it to a name of a control that already exists in your form frevvo will not allow it. However there are several ways 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
Under any of these circumstances you may have unexpected results if these controls are used in rules. The solution is to edit their names to make them unique. Note that 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.
Rule Identifiers
As described above, rules refer to form controls using a Name. Let's say you have a control to which you have assigned the Name 'T'. You can refer to properties of this control in rules using identifiers.
Rules identifiers must always be of the form Name.<property>. In the current version of frevvo, the following properties are supported:
- 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 the red asterisk. (NOTE: only effects palette controls and not controls generated from XSD schema data source) In v3.4 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.
- 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.
- 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.
- form.unload : This property is true when the users clicks the form's submit button. It is useful for setting control values just prior to the form's Doc Actions and Form Actions are executed.
Examples of identifiers used in frevvo rules are:
- FirstName.value
- BillingAddress.visible
- Email[1].value
- Email[i].visible
The latter two are examples of repeating controls. We will discuss repeating controls in more detail below. Note that the case of the properties is important. FirstName.value is a valid rule identifier but FirstName.Value or FirstName.vAlUe are not.
When are rules executed ?
When you create or edit a rule, frevvo figures out the list of controls and properties of those controls that the rule depends upon. The rule will be automatically executed whenever there is a state change that is relevant to the rule. Rules are also executed sequentially in a top to bottom order as they are seen in the rules panel.
Note that rules can trigger the execution of other rules. So, if a rule, R1, sets the value of a control with Name A, and there is a rule R2, that depends on A.value, then rule R2 will be triggered and executed.
A rule will typically refer to one or more form controls and their properties and it will be executed if any of those properties change value. Note that Rules are not fired when the page is loaded. See form.load for more details. For example, the rule below will only be executed when N1.value changes its value.
if (N1.value > 0 || N2.value > 0) {
T.value = N1.value + N2.value;
}
Now let's assume a use case where you want to show a message if 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'. One could write the rule:
if (!E.valid) {
// code to show message here.
}
The code above would not work as expected. E is a required field and therefore E.valid initial value is 'false' since the field is in initially empty. When the user enters an invalid email address, E.valid would still have the value 'false' and the rule would not execute since there is no state change. The code below would work properly.
if ((E.value.length > 0) && (!E.valid)) {
// code to show message here.ita
}
Now, the 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 rule will be executed and the message will be shown.
Infinite Loops
It's easy to create rules that run forever. An example, is a rule that updates A.value based on B.value and another rule that updates B.value based on A.value. They could continually trigger each other.
The frevvo server will prevent this from happening by setting an execution time limit for each rule. Any rule that takes longer than 5 seconds to execute will be forcibly stopped. Note that this is a very lengthy period of time for most computational tasks and the vast majority of rules will not be impacted by this constraint. However, since frevvo is a hosted site that may be simultaneously used by numerous users, there is a time limit imposed on these computations.
Rule Timeout
By default a rule that takes longer to execute then 5 seconds will be timed out by the Form Server. Customers using the in-house download version can customize this timeout. This is often necessary when rules have to perform longer running operations such as sending email messages, database stored procedures, etc... To configure the timeout add the following line to your web application containers property file. For the frevvo-tomcat bundle this file is .../tomcat/conf/Catalina/localhost/context.xml.default and is specified as follows:
<Parameter name="frevvo.rule.timeout" value="5000" override="false"/>
To set the timeout to 15 seconds set value="15000"
What is not permitted in a rule?
Setting the value of a control to an array or to a random JavaScript object is not allowed.
Select Controls
Radio controls, dropdowns and checkboxes are all examples of select controls. Radio & dropdown controls are single select. That is, if one item in the dropdown is selected then all other items in the dropdown are deselected. The same is true for a radio. Only one radio button can be depressed at any time. Thus the ID.value of radios and dropdowns are similar to the other input and output controls. The value is a single item.
Checkbox controls are multi-select. That is, multiple items can be selected at any given time. Thus the ID.value of a checkbox is an array. Therefore on checkboxes a valid expression is ID.value.length which returns the number of items in the value array. And ID[0].value would retrieve the 1st item in the list and ID[1].value the 2nd and so on. If you have a checkbox control with only one checkbox and that checkbox is unchecked, the array will contain no elements. For an checkbox control a useful expression is ID.value.length == 0. Note that ID.length is not a valid expression. Also since a checkbox control is an array it is not a valid expression to write ID[0].value == . Because if at option in the checkbox control is unchecked, it's value will not be an empty string. It will simply not exist in the array.
Initial Control State
Every control in your form has an initial default property states for the visible, expanded, value, valid & enabled properties. However you can change a controls initial state in frevvo’s form designer Edit tab. A control’s initial state 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 via the controls edit property panel. The edit property contains checkboxes for visible and enabled for controls on which those properties make sense like input controls.
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.
Rules allow 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, dropdown, checkbox) controls.
Here is an example that shows the syntax of the http.get. This 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. Then x can be used in the rule as necessary. In this case it is 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;
Imagine another example 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 dropdown 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/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 could be used in a 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>";
} else
{
m.value = "<center>Invalid username or password</center>";
}
}
It is important to note that the http.get is accessing your http service via a URL. Certain characters must be encoded in order to correctly pass thru via an HTTP URL. [| W3 Schools] provides one good reference on this topic. 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 need 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");
For complete details of integration with your backend systems to provide dynamic data into your forms, see the section on integration.
Relative URIs
The dynamic content described above requires an http get to a specific URI service returning a JSON object. The examples above specified absolute URI paths. In Live Forms v3.3 and later version it is possible to use a relative path.
Assuming the frevvo Form Server is running on http://www.myhost.com, http.get(‘http://www.myhost.com/path/to/resource’) may instead be written as http.get(‘/path/to/resource’).
For example:
eval('x=' + http.get('http://<webhost>/database/mydb/getPrices'));
In this example the path to the URI service is an absolute hard coded path. When the service is running on the same host as the frevvo form server you may use a relative URI. One common scenario where this is applicable is for Live Forms In-house customers who have also installed the frevvo database connector. In this case the rule is best written as follows because it becomes portable if you move your form server from one <webhost> to another <webhost> as is common when running under development servers and moving to production servers.
eval('x=' + http.get('/database/mydb/getPrices'));
Templatized URIs
The URIs used in a http get very often contain variables. For example, the service getPrice takes as an argument an item name:
eval('x=' + http.get('http://<webhost>/test/json/getPrice?itemName=' + itemName.value));
Price.value = x.price;
In Live Forms v3.3 and later this URI can be shortened using a simplified template syntax:
eval('x=' + http.get('http://<webhost>/test/json/getPrice?itemName={itemName}'));
Price.value = x.price;
For example assuming that when the form is used the field named itemName contains the value 'laptop', then using examples of both absolute and relative URIs and assuming that the service is running on http://www.frevvo.com:
http.get('/path/to/service/{itemName}')
=> 'http://www.frevvo.com/path/to/service/laptop'
http.get('http://www.frevvo.com/path/to/service/{itemName}')
=> 'http://www.frevvo.com/path/to/service/laptop'
Note that since templates need not be bound to form controls the value for 'itemName' may be passed into the form using _data rather than as a value entered into the field by the user. If instead you use the syntax itemName.value in your URI then a control named itemName must exist as a field in your form.
This can be a very good way to dynamically configure your service's location rather than hard-coding the location into the rule. This form was loaded with the Url parameter &_data(myBaseUrl:'http://www.myhost.com')
http.get('{myBaseUrl}/path/to/service') => 'http://www.myhost.com/path/to/service
In this case since we do not want a form field to display myBaseUrl we use a template rather then adding a special field just for the purposes of passing the base Url into the rule.
Url Parameters Accessed in Rules
Url parameters passed into your form via the _data frevvo parameter can be accessed in rules several ways. If &_data(FirstName:'Joe') was added to your form Url, then:
- FirstName.value - only for parameters bound to a control in your form
- {FirstName} - only for parameter used in http get templatized URI
- _data.getParameter('FirstName') - if used anywhere else in a rule other than a URI.
Option 2 & 3 are available for both bound and unbound controls. So choose whichever approach is the simplest for you.
Rule Examples
Rules are probably best described using a number of examples.
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
if (N1.value > 0 || N2.value > 0) {
T.value = N1.value + N2.value;
}
This rule will automatically fire whenever the user types something in N1 or N2 and will set the value of T appropriately. You can use any legal JavaScript operators in the expression such as subtraction or multiplication. However, it's important to ensure that the calculated value is valid with respect to the type of T. For example, if T was of type integer and the computed value of the expression was decimal (such as 1.5), then the rule would be attempting to set an invalid value in T. This is an error. The rule will set the value as requested, but will mark the field as invalid and take appropriate action such as disabling the submit button, displaying the control with a red background etc. Also, if controls are added to the form from the palette, it is important to ensure they have the correct type. For example, for a numeric calculation as described above, the controls should be of type Numeric (found in the palette).
Show/Hide Billing Address
You have a form with two controls and you have assigned them Names B and S respectively. B is a checkbox with a single option - Yes. If checked the user wishes to enter a different billing address in S and you want to display S. The rule would be written as
if (B[0].value == 'Yes') {
S.visible = true;
} else {
S.visible = false;
}
This rule will automatically fire whenever the user checks or unchecks B and will show/hide the billing address section S. Again, you could use any legal JavaScript expression to compute the visible property of S as long as it evaluates to a boolean true or false value.
In this example, you would typically set the checkbox B to be initially unchecked and the section S to be initially hidden.
Enable/disable a question
You have a form with two controls and you have assigned them Names B and Q respectively. B is a checkbox with a single option - Yes. . If checked the user is a smoker and you wish to ask an additional question in Q. The rule would be written as
if (B[0].value == 'Yes') {
Q.enabled = true;
} else {
Q.enabled = false;
}
This rule will automatically fire whenever the user checks or unchecks B and will enable/disable the question in Q. Again, you could use any legal JavaScript expression to compute the enabled property of Q as long as it evaluates to a boolean true or false value.
In this example, you would typically set the checkbox B to be initially unchecked and the control Q to be initially disabled.
Compute Subtotals for Repeating Items
This rule is an example of working with repeating items. Let's say, you have a form with a repeating section representing an Item that the user may purchase. Each section has a Price (with Name P), a Quantity (Name Q) and a Subtotal (Name S). There are multiple items on the page and the number of items on any given page is unknown. The price field is filled in automatically. When the user enters a value in the quantity field for any item, you wish to compute the subtotal.
The rule would be written as:
for (var i = 0; i < S.value.length; i++) {
if (Q[i].value > 0) {
S[i].value = Q[i].value * P[i].value;
}
}
This rule will automatically fire whenever the user enters a value in the quantity field for any item. It will compute the subtotal for each item, for which the quantity is greater than 0 and fill in the subtotal field for that item with the computed value. If a particular item does not have a quantity, the subtotal is not computed.
Compute an Invoice Total
Consider the same form as the example above. Let's say you have a control named Total with Name T. You want to set the value of Total to be the total invoice price, which is the sum of all the computed subtotals above. This rule would be written as:
var tot = 0;
for (var i = 0; i < S.value.length; i++) {
tot = tot + S[i].value;
}
T.value = tot;
This rule will fire whenever a subtotal is updated, for example, when it is updated via the rule above. It will add the values of all the subtotals to arrive at an invoice total. Note that you must use a temporary variable to compute the total. If you write the rule as:
T.value = 0;
for (var i = 0; i < S.value.length; i++) {
T.value = T.value + S[i].value;
}
it will not work correctly. This is due to internal limitations in the way rules are evaluated.
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 assigned TypeId 'P' and the product ID dropdown control was assigned TypeId 'ID'
The 1st rule "Load Products" populates both the visible and hidden dropdowns with options from a database.
Load Products:
--------------
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 Product description dropdown
Select Product ID Rule:
-----------------------
if (Products.value.length > 0)
{
var i;
for (x in Products.options) {
if (Products.value == Products.options[x])
i = Products.options.indexOf(Products.options[x]);
}
PID.value = PID.options[i] + '';
}
In v3.4 rules using hidden dropdowns to keep descriptive option labels visible to the user while keeping cryptic database values hidden are often no longer necessary. In v3.4 dropdown options can now have values distinct from the human visible option labels. The above can now be achieved with a single simpler rule:
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.
if (S.value.length > 0) {
eval('x=' + http.get('http://localhost:8182/products/?category=' + S.value));
P.options = 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.
var i;
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, frevvo automatically adds a blank option so the dropdown initially shows no choice by default. To reset the dropdown to this state via a rule, you must set the dropdown control's value to null not the empty string. Since the empty string is not a valid option. Type size form field had a typeId named 'size'. And the selection form field when set to a new value requires the size field to be reset back to the default blank option.
if ((selection.value != Hselection.value)
&& (!form.preload))
{
// Store new Hselection in hidden field for use in next comparison
Hselection.value = selection.value;
size.value = null;
}
Checkbox Options
Checkbox controls are different from all other frevvo 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.
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.
if (colorPalette.value.length > 0)
{
colorChoice.value = 'Thank you for choosing colors';
}
else
{
colorChoice.value = 'Please choose colors...';
}
Checkbox Options
This rule makes visible/invisible a control based on which checkbox options a user selects. This form contains a multi select checkbox named Structures. If the user selects the option "Detached Garage" or "House", we want to make visible a text field named Details.
Again since a checkbox is multi select, it is handled as an array. The array will contain all selected (checked) options.
It is important to note that when a checkbox is added to the form from the palette and its options are multiple words containing spaces, the option array has converted each space character to the '_' character. We must make the comparison as shown below. Checkbox controls from schema do not have space replaced with '_'.
var found = false;
for (var i = 0; i < Structures.value.length; i++)
{
if (Structures[i].value == 'Detached_Garage' ||
Structures[i].value == 'House') {
found = true;
break;
}
}
if (found == true) {
Details.visible = true;
} else {
Details.visible = false;
Details.value = null;
}
Note that when we hide Details we also clear its value. This is because the user may have selected one of the Structures checkboxes that made Details visible AND entered a value into Details. And then they may have changed their minds and uncheck the option that caused Details to become visible. If you don't want the value entered into Details to be in your form submission, clear the value when hiding it.
Checkbox Initialization
Since checkbox options are multi-select, in order to select multiple options via a rule you must use this syntax. In this example CB is the name of a checkbox controls with the following options: red, green, blue. This rule selects all of the options.
frevvo v3.1 and later versions you need to use an array syntax.
CB.value = ['red', 'green', 'blue'];
Repeating Checkboxes
Checkboxes inside repeat controls must be treated as an array (each checkbox control's values) of checkbox option values which is inside another array (the repeating checkbox control itself). This form example has a repeating section containing two controls -- Message which is a text control and AreYouAttending which is a checkbox control with a single option 'yes'. To access the selected options the syntax is:
AreYouAttending[i].value[0] == 'yes'
for (var i = 0; i < AreYouAttending.value.length; i++)
{
if (AreYouAttending[i].value[0] == 'yes') {
Message[i].value = Name.value +
' is attending event #' + i;
}
}
Dynamic Labels, Help, Hints
You can set the value of control labels, help and hint dynamically in a rule. For example imagine you do not know the label, help or hint at design time but would rather set it dynamically when a user opens your form.
if (form.load)
{
Text99.label = 'New Label';
Text99.hint = 'New Hint';
Text99.help = 'New Help';
}
In the above example the label, help and hint is still hard-coded. It's just being set from the rule rather than in the form designer controls' properties. To make this more useful you can initialize these properties from _data parameters:
if (form.load)
{
Text99.label = _data.getParameter('label');
Text99.hint = _data.getParameter('hint');
Text99.help = _data.getParameter('help');
}
Since _data.getParameter enables access to values passed to the form that are not bound to actual controls this is often a very useful pattern.
Visible/Invisible
This rule makes the message control nickNameThankYou visible when the user enters a value into the nickName input text control. And then hides the message control if the user deletes the value in nickName.
if (nickName.value.length > 0 )
{
nickNameThankYou.visible = true;
}
else
{
nickNameThankYou.visible = false;
}
Visible/Invisible Section
Often section controls contain many inner controls. For example imagine a form that contains a person's medical history. One of the questions on the form asks if the patient uses a hearing aid. If they answer yes then you want to collect more details on their hearing aid usage such as left ear, right ear, bilateral; hearing aid brand; etc... If they answer no then you want to hide all the questions specific to hearing aids. Also when they answer is yes you want to require them to answer all the hearing aid detailed questions.
Imagine this example form has a section named HearingAid. By default HearingAid visible is set to false in the form designer.
In v3.3 and prior, when they answer yes you must set HearingAid.visible=true AND also each required field inside the section to field.required = true. If they then change the answer to no then another rule makes the HearingAid.visible=false also need to set all field.required=true again. If the HearingAid section contains many child controls this rule becomes very long and tedious to write
In v3.4 we can simplify this by using the new required property for sections. In the designer default all controls that must be answered inside HearingAid to required. Default the HearingAid section to not required and not visisble. Your rule can be much simpler. By setting HearingAid.required=false all the inner controls recursively also become required=false.
if (useAid.value == 'no') {
// Hide
HearingAid.visible = false;
HearingAid.required = false;
} else {
// Show
HearingAid.visible = true;
HearingAid.required = true;
}
NOTE: It is not currently possible to effect required for controls from XSD schema. This functionality will be added in a future release of Live Forms. See the documentation for Data Sources and Schemas for details on implementing a Show/Hide rule with XSD controls.
Select Tab
This rule makes a specific tab the selected tab based on the choice of a radio control. The radio is named SelectTab and has three options: person, auto, home. The tabs are named personTab, autoTab and homeTab. Tabs also can be select based on trigger controls or other input controls using the same method show here. Try this tabbed form to see the rule in action or download this form using the 'rules' tag.
if (SelectTab.value.length > 0)
{
autoTab.selected = false;
homeTab.selected = false;
personTab.selected = false;
if (SelectTab.value == 'Auto')
autoTab.selected = true;
else if (SelectTab.value == 'Home')
homeTab.selected = true;
else
personTab.selected = true;
}
Next Tab
This form contains a trigger control at the bottom of each tab labeled "Next". When "Next" is clicked the trigger rule executes and makes the next tab the selected tab. This assists the user in navigating through the form. The Tabs are named T1, T2, T3, T4. The trigger controls are named C1, C2, C3
// Navigate Tabs
if (C1.clicked) {
T2.selected = true;
} else if (C2.clicked) {
T3.selected = true;
} else if (C3.clicked) {
T4.selected = true;
}
Expand/Collapse Section
This form has three sections. The first section is expanded and the 2nd and 3rd are collapsed. When the user files in the 1st section they click a "Next" trigger control which causes that section to collapse and the next section to expand. The trigger controls are named next1 and next2. And the sections are named: step1, step2, step3. Try this membership form to see the rule in action or download this form using the 'rules' tag.
if(next1.clicked)
{
step1.expanded = false;
step2.expanded = true;
}
if(next2.clicked)
{
step2.expanded = false;
step3.expanded = true;
}
Multiple Choice
This rule makes the appropriate input text controls visible depending on the choice a user makes in a radio option controls searchChoice.
if (searchChoice.value == 'Organizations')
{
orgname.visible = true;
firstname.visible = false;
lastname.visible = false;
clientId.visible = false;
}
else if (searchChoice.value == 'Individuals')
{
orgname.visible = false;
firstname.visible = true;
lastname.visible = true;
clientId.visible = false;
}
else if (searchChoice.value == 'Client ID')
{
orgname.visible = false;
firstname.visible = false;
lastname.visible = false;
clientId.visible = true;
}
Triggers & Dynamic Options
This rule is executed when the user clicks the trigger controls with Name search. It then dynamically sets options on a dropdown list control with Name coffeeShopList.
if (search.clicked)
{
coffeeShopList.options = ['Koffee', 'Starbucks', 'Willoughbys', 'Dunkin Donuts'];
}
Now replace the hard coded list of coffee shops with a rule that invokes an http.get. This must return an X-JSON header which containing a JSON object. The object is evaluated and assigned to the variable x. In this case the JSON object contains an options field of type array. See the section on dynamic content for more details.
if (search.clicked)
{
eval('x=' + http.get('http://<webhost>/getCoffeeShopList'));
coffeeShopList.options = x.options;
}
Value Change & Dynamic Options
This rule dynamically sets the options in a dropdown list based on the value selected in another form field. This form contains three fields named Products, Series and Model. The series options are set dynamically based on the product selection. Also when a new product is selected we enable the series dropdown and both clear and disable the model dropdown. This form contains other rules which set the models based on the selected series. Look for the frevvo Gallery form named HP Support - 2 under the dynamic forms keyword.
if (product.value == 'Laserjet Printers')
{
series.options = [' ', 'Laserjet5 series', 'Laserjet6 series'];
series.enabled = true;
model.options = [];
model.enabled = false;
}
Verify User
This rule executes when the user enters a value into the Username text field. It invokes a Url that returns a JSON object that has a boolean field name exists that is set to true if the user already exists. If the user already exists this rule then sets the value of a message control, makes that message control visible on the form and sets the Username valid property to false so that Username field displays as invalid to guide the user to make a correction. See the section on dynamic content for more details.
if (U.value.length > 0) {
eval('x=' + http.get('http://<webhost>/uniqueUser?username=' + U.value));
if (x.exists) {
M.value = 'User: ' + U.value + ' already exists';
M.visible = true;
U.valid = false;
} else {
M.visible = false;
}
}
Digital Signature
This form uses a rule to pass a username and password to a LDAP Active Directory authentication service. If authentication fails the form makes a error message control visible. If authentication succeeds the form disable the username form field and replaces the password field with a date field set to the current date. The form contains a trigger control named sign, username and password fields name u and p respectively, a date field named d and a messsage field named m.
if (sign.clicked) {
// passwords may contain characters that need url encoding
var p_encode = encodeURIComponent(p.value);
eval('x=' + http.get('http://<myhost>/authServices/signForm?username=' + u.value + '&password=' + p_encode));
if (x.auth) {
var dt = new Date();
var day = dt.getDate();
var month = dt.getMonth() + 1;
var year = dt.getFullYear();
d.value = month + '-' + day + '-' + year;
d.visible = true;
u.enabled = false;
p.visible = false;
sign.visible = false
m.visible = false;
} else {
m.visible = true;
}
}
The authService is an example HTTP servlet that returns a JSON response.
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String username = request.getParameter(REQUEST_SIG_USERNAME);
String password = request.getParameter(REQUEST_SIG_PASSWORD);
password = URLDecoder.decode(password, "UTF-8");
// Authenticate Signature
authenticateUser(response, username, password);
} catch (Exception e) {
throw new ServletException(e);
}
}
private void authenticateUser(HttpServletResponse response, String u, String p) {
if (realm.authenticate(u, p) == null)
response.addHeader(RESPONSE_JSON_HEADER, "{auth:false}");
else
response.addHeader(RESPONSE_JSON_HEADER, "{auth:true}");
}
Here's another example form that requires a doctor's signature. This shows how the form works in use mode. The first image contains a dropdown to select one of the doctor's authorized to sign the form and a text control where they enter their PIN code.
This image shows the case where the doctor entered an invalid PIN and the error message becomes visible.
This image shows the case of a valid PIN. Today's date is entered into the date control via the rule and made visible and disabled from edit. The username dropdown is disabled and the PIN and Sign controls are hidden.
Calculate Net Worth
This form contains two rules. One is adding values entered into a column of assets and a column of liabilities and calculatng netWorth. The 2nd rule is checking the value of netWorth and displaying an error message and marking netWorth invalid if liabilities exceed assets since the form designer does not want the form to be submittable in that state.
if (netWorth.value < 0)
{
assetsExceedLiabilitiesMsg.visible = true;
netWorth.valid = false;
}
else
{
assetsExceedLiabilitiesMsg.visible = false;
netWorth.valid = true;
}
When a rule sets <control>.invalid the control background turns red and the submit button greys out just as if the user had entered an invalid value into a phone control. frevvo treats it exactly the same way. This is a good way to dynamically control your form's valid state.
Dates and Times
Working with dates & times is flexible using business rules. 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.
// Calculate Hospital Stay Duration
if (A.value != '' && D.value != '') {
var da = A.value.split('-');
var Ams = new Date(da[2],da[0]-1,da[1]);
da = D.value.split('-');
var Dms = new Date(da[2],da[0]-1,da[1]);
if (Ams > Dms) {
Days.value = 'Discharge date must be after Admission Date';
} else {
Days.value = (Dms - Ams) / (1000*60*60*24) + ' days';
}
}
// Initialized Discharge Date to Today
if (form.load)
{
var today=new Date()
var m = today.getMonth() + 1;
var todayStr = m + '-' + today.getDate() + '-' +
today.getFullYear();
A.value = todayStr;
}
Repeat Item Added
This rule executes when a new item is added to a repeat. Imagine your form contains a repeating section named Employee with name Erepeat. NOTE: that the name Erepeat is set on the Repeat control and not on the Section control. The Employee section control contain many controls such as Name, Phone, etc.. and a dropdown control named Manager with typeId Managers. It also contains a radio control labeled Employee Shift with typeId ES whose options have been set to 'Day' and 'Evening'.
frevvo will execute this rule each time a user clicks "+" on the repeat to add a new item. Here we want to default the Employee Shift ES to the value 'Day', and populate the Manager dropdown dynamically with values from the frevvo Database Connector.
if (Erepeat.itemAdded)
{
var index = Erepeat.itemIndex; // which item is this in the list
ES[index].value = 'Day'; // default the employee shift to day
var baseURL = 'http://www.myhost.com:8080/database/';
// Manager Dropdown
eval('x=' + http.get(baseURL + 'Manager'));
var opts = ['']; // default 1st option to blank
for (var i=0; i < x.resultSet.length; i++) {
if (x.resultSet[i]) {
opts[i+1] = x.resultSet[i].lastname+ ", " + x.resultSet[i].firstname;
}
}
Managers[index].options = opts;
}
Repeat Item Added
This rule executes when a new item is added to a repeat. Imagine your form contains a repeating section named Employee with name Erepeat. NOTE: that the name Erepeat is set on the Repeat control and not on the Section control. The Employee section control contain many controls such as Name, Phone, etc.. and a dropdown control named Manager with typeId Managers. It also contains a radio control labeled Employee Shift with typeId ES whose options have been set to 'Day' and 'Evening'.
frevvo will execute this rule each time a user clicks "+" on the repeat to add a new item. Here we want to default the Employee Shift ES to the value 'Day', and populate the Manager dropdown dynamically with values from the frevvo Database Connector.
if (Erepeat.itemAdded)
{
var index = Erepeat.itemIndex; // which item is this in the list
ES[index].value = 'Day'; // default the employee shift to day
var baseURL = 'http://www.myhost.com:8080/database/';
// Manager Dropdown
eval('x=' + http.get(baseURL + 'Manager'));
var opts = ['']; // default 1st option to blank
for (var i=0; i < x.resultSet.length; i++) {
if (x.resultSet[i]) {
opts[i+1] = x.resultSet[i].lastname+ ", " + x.resultSet[i].firstname;
}
}
Managers[index].options = opts;
}
Repeat Item Added - Collapse Other Items
This rule executes when a new item is added to a repeat. This form contains a repeating section with a templatized label. It is nice to collapse the other items when adding a new item to keep the repeat list small and grid-like. Medrepeat is the name of the repeat control. Medication is the name of the section control inside the repeat.
if (Medrepeat.itemAdded)
{
var index = Medrepeat.itemIndex;
for (var i = 0; i < Medication.value.length; i++) {
if (i != index)
Medication[i].expanded = false;
else
Medication[i].expanded = true;
}
}
form.load
Rules can be used to initialize field values. This is a very useful feature and is often used to dynamically populate dropdown options from a database.
Rules using itemAdded only execute for repeat items added when the user clicks +, and for those added from an initial instance document (See Document URIs). It does not execute for those items that you have added to your form in the Form Designer. You can either added defaults directly via the form designer or add a 2nd rule to your form as follows.
These two rules together initialize the dropdown fields inside a repeat that are already in the form via the Form Designer, as well as those added each time a user clicks "+" on the repeat to add a new item & via initial documents. These controls are initialized based on a value set in another field.
'''1st Rule - Default Items'''
if (form.load)
{
// The form contains two repeat items by default.
if (department.value == 'Marketing') {
Managers[0].options = ['Joe', 'Mary', 'Stan', 'Cindy'];
Managers[1].options = ['Joe', 'Mary', 'Stan', 'Cindy'];
}
if (department.value == 'Sales') {
Managers[0].options = ['Lou', 'George', 'Wendy'];
Managers[1].options = ['Lou', 'George', 'Wendy'];
}
}
'''2nd Rule - Items Added'''
if (Erepeat.itemAdded)
{
var index = Erepeat.itemIndex; // which item is this in the list
ES[index].value = 'Day'; // default the employee shift to day
if (department.value == 'Marketing') {
var opts = ['Joe', 'Mary', 'Stan', 'Cindy'];
}
if (department.value == 'Sales') {
var opts = ['Lou', 'George', 'Wendy'];
}
Managers[index].options = opts;
}
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.
One common example use is for an order form order number. You may only want to assign a unique sequential order number to each order submission. You could initialize the form's order number when the form loads using form.load. However if someone start filling in the order form but never submit it you do not want to consume the next order number in sequence if it will never be used. Using form.unload you can assign the number after the submit button click but before the form data is submitted.
Here OrderNum is the name of a invisible control.
if (form.unload)
{
eval('x=' + http.get('http://<webhost>/json/getNextOrdernum'));
OrderNum.value = x.num;
}
Repeat Item Initialization
The rule above was one example of initializing a newly added repeating control with a default list of options. This same concept is useful if you want to initialize a repeating control's value. When you add a repeat to your form in the Form Designer you can set a default value in any of those repeating controls visible in the designer. However when the user clicks "+" while using the form to add an additional item the default entered in the Form Designer is not automatically used in this new item. In order to accomplish this you can add a simple rule as follows:
This rule initializes the value of one of the fields in the repeat to a default of '0'. RepeatTrack is the name of the repeat control contain the input control named albumOnly. This rule will execute each time a new RepeatTrack item is added when the user clicks "+". NOTE that itemAdded and itemIndex are properties of the Repeat control.
if (RepeatTrack.itemAdded)
{
var index = RepeatTrack.itemIndex;
albumOnly[index].value = 0;
}
Again, to initialize repeat items already on your form in the Form Designer by default, either enter your initial default values directly into the in the Form Designer or add this rule.
if (form.load)
{
for (var i=0; i < albumOnly.value.length; i++) {
albumOnly[i].value = 0;
}
}
This rule takes into account a repeat where min > 1. If min is 0 or 1, you can simplify this further by removing the from loop and simply have albumOnly[0].value = 0 inside the if (form.load).
Repeat ItemAdded by Init Doc
ItemAdded also executes when frevvo adds items found in an init doc. You may want to only initialize items added when the user clicks "+" on the form. And not those added from an initial document. This form contains a Mailing Label that repeats. Each label needs a unique ID assigned. However once the form is submitted the assigned IDs are saved in the database via the form's Doc URI. When the form loads it adds items automatically from rows in the database. They already have assigned Ids. We only need to assign new Ids in the sequence when the user manually adds a new Mailing Label by clicking the "+" button on the form. MLrepeat is the typeId for the Mailing Label repeat. MLmid is the typeId of the ID field in the repeat.
if (MLrepeat.itemAdded)
{
var index = MLrepeat.itemIndex;
// This rule is fired both when the user clicks "+"
// and when frevvo adds items found in the init doc.
// Need to assign new mid only when user clicks "+"
// New items added via "+" will have a zero length value.
if (MLmid[index].value.length == 0) {
// Assign unique ID to label so it can be referenced
// in RI Mailing Labels field
// Count the number of existing mailing labels on the form
var maxId = 0;
for (var i=0; i < MLmid.value.length; i++)
{
if (MLmid[i].value > maxId) {
maxId = MLmid[i].value;
}
}
var next = parseInt(maxId) + 1;
MLmid[index].value = next.toFixed(0);
}
}
Search Popup
frevvo forms can initialize dynamically from backend systems. A common form design pattern is the master/detail. An example of master/detail is a form that contains an order number or employee Id. When the user enters an existing Id into the form field you want all other form fields to populate dynamically from values in a database. This is done using a form created from XSD data source generated by the frevvo database connector. This part of the master/detail form design pattern needs no business rule. It happens automatically using the Doc Action manually set document URIs. See the Database Connector Tutorial for complete detail on how to initialize your form using a Doc Action document URI to your database.
This form was created from employee.xsd generated by the frevvo database connector. The master Id is a control from that XSD named racfid. The key to this design pattern is in using the master Id in the form's doc action document URI. In this example the form's doc action document URI for the employee document is set to: http://localhost:8082/database/myqset/employee?racfid={racfid}.
Often the master Id is a cryptic number not easily remembered by people using your form. It is a common and useful form design pattern to populate the master Id using a lookup search.
Here is an example form that allows user to view existing employee records and to update their information.
If you know the RACF ID for an employee you can simply type it into that field. If the RACF ID is found in the database the form will automatically populate all other fields from the database (because of the doc action document uri setting). However if you do not know the employee's RACF ID you can click the Find Employee trigger.
This trigger control is named FindEmployee and fires the following rule that makes the search condition section control visible.
//Show Employee Search Criteria
if (FindEmployee.clicked)
{
EmployeeSearch_s1.visible = true;
EmployeeSearch_s1.expanded = true;
}
The section control contains controls that are the search critiera for finding a RACF ID based on other pieces of information you may know about an employee such as name, type, email address. The values entered into the search criteria can be partial values. For instance entering a name "Smith" will find all employees whose name contains the letters "Smith". If you also select email "frevvo" it will find all employees whose name contains "Smith" and have an email address containing the string "frevvo".
This is the rule that fires when you click the trigger control named Search.
//Search Employee database using criteria
if (Search.clicked)
{
eval('x=' + http.get('database/myqset/findEmployee?name={name_s1}&type={type_s1}
&racfid={id_s1}&email={email_s1}'));
var opts= [];
for (var i=0; i < x.resultSet.length; i++) {
if (x.resultSet[i]) {
opts[i] = x.resultSet[i].racfid + "=" +
x.resultSet[i].name + ", " +
x.resultSet[i].type;
}
}
SearchMsg.value = x.resultSet.length +
' Matches Found. Change your criteria and click "search" to try again.';
SearchMsg.visible = true;
SearchResults.options = opts;
SearchResults.visible = true;
}
The Search returns one or more matches and dynamically populates a dropdown control named SearchResults. You can change the search criteria to narrow or expand you search. When you select one of the matches from the SearchResults dropdown this 3rd rule executes to copy the selection into the RACF ID control.
//Select from Search results
if (SearchResults.value.length > 0)
{
racfid.value = SearchResults.value;
// Hide Employee Search and clear values
EmployeeSearch.visible = false;
SearchMsg.visible = false;
SearchResults.visible = false;
SearchResults.options = [];
}
Once the value is copied into RACF ID the form automatically loads all other values in the form from the database. This is due to the form action document Uri setting.
The values in the employee loaded into the form can now be edited. When the users clicks the form's submit button the values will automatically be updated in the database record. This is due to the form action document Uri setting.
Database Connector REST Services
The database connector REST services can be invoked via a rule. The http.get returns a JSON object that contains a resultSet array containing each row returned from the SQL query. For details on configuring the database connector see the documentation for Connecting to your database. For an overview of using JSON to dynamically populate dropdown controls click here.
In this example the database connector contains the following three <query> elements in configuration.xml:
<query name="lastnames"> <statement> <retrieve>SELECT lastname FROM Customer</retrieve> </statement> </query> <query name="firstnames"> <statement> <retrieve>SELECT firstname FROM Customer</retrieve> </statement> </query> <query name="names"> <statement> <retrieve>SELECT firstname,lastname FROM Customer</retrieve> <statement> </query>
The form contains a radio control with Yes/No options and a typeId getCustomerList. When the Yes option is clicked this rule executes the http get to the database connector URI http://<host>/database/lastnames. The returned JSON resultSet object is an array of all the lastnames returned by the select specified above in configuration.xml. The resultSet is then used to set the options in a dropdown control with typeId customerLastNames.
if (getCustomerList.value == 'Yes')
{
eval('x=' + http.get('http://<host>/database/lastnames'));
var opts= [];
for (var i=0; i < x.resultSet.length; i++) {
if (x.resultSet[i]) {
opts[i] = x.resultSet[i].lastname;
}
}
customerLastNames.options = opts;
}
The case used in the select statements much be the exact case used in your rule. For example:
if query is: select lastname from Customer ,then rule must use x.resultSet[i].lastname
if query is: select LastName from Customer,then rule must use x.resultSet[i].LastName
If the database connector is running on the same <host> as the frevvo form server consider the benefits of using a Relative URI.
This example is similar except the URI uses the names query which returns both first and last names for each row in the customer table.
if (getCustomerList.value == 'Yes')
{
eval('x=' + http.get('http://<host>/database/names'));
var opts= [];
for (var i=0; i < x.resultSet.length; i++) {
if (x.resultSet[i]) {
opts[i] = x.resultSet[i].firstname + " " + x.resultSet[i].lastname
}
}
customerFullNames.options = opts;
}
This example is similar except the event that triggers the execution of the rule is an initial instance document loaded into the form when it opens. See the section on Document URIs for details on configuring your form to load an instance document. This rule executes before the form becomes visible in the browser. Thus the dynamic options are populated prior to the user seeing the form.
The form's Document URI read method is set as follows. When the form loads frevvo will perform a get to this URI. Notice that the URI specifies the database connector. So the values come from a database resource. Also in this case the URI contains a parameter so you can indicate which particular document to get from the DocMgmt resource.
http://<host>/database/DocMgmt?docId={docId}
The database configuration.xml contains the following <query> element.
<query name="DocMgmt" autocreate="true">
<create>
<!-- Maps to the HTTP POST method -->
INSERT into documents SET docId='{docId}'
</create>
<retrieve>
<!-- Maps to the HTTP GET method -->
SELECT docname,docId FROM documents WHERE docId='{docId}'
</retrieve>
<update>
<!-- Maps to the HTTP PUT method -->
UPDATE documents SET docId='{docId}',docname='{docname}' WHERE docId='{docId}'
</update>
<delete>
<!-- Maps to the HTTP DELETE method -->
DELETE from documents WHERE docId='{docId}'
</delete>
</query>
First, the URL http://<host>/database/DocMgmt/schema was opened in the browser to automatically generate an XSD describing the resultset returned from the DocMgmt <retrieve> method. This XSD was then uploaded into the frevvo application and the resultSet type added to the form. The docname control from that schema was edited and given a typeId 'docname'.
The form URL was then opened in the browser. The URL was obtained by clicking the Embed button
for this form and copying the URL from the displayed dialog box. A query parameter &docId=02 was appended to that URL to specify the exact document resource to load when the form loads. Notice that the query parameter name exactly matches the template name '{docId}' in the form's Document URI above.
When the form loads in the browser, frevvo initializes the docname controls from the database resource. If a document is found, the docname control will have a value whose length is > 0. This triggers the following rule which executes the firstnames query's retrieve method to populate the dynamic dropdown options in the customerFirstNames form field.
if (docname.value.length > 0)
{
eval('x=' + http.get('http://<host>/database/firstnames'));
var opts= [];
for (var i=0; i < x.resultSet.length; i++) {
if (x.resultSet[i]) {
opts[i] = x.resultSet[i].firstname;
}
}
customerFirstNames.options = opts;
}
Migration Issues
Options
When upgrading frevvo Live Forms from prior version to v3.4 any rules written using string comparison against <control>.options[x] will need to be re-written. In prior versions the options[] array contains only the label string. In v3.4 the options[] array contains both the option label and the option value in the syntax <value>=<label>. Rules written prior to v3.4 may fail unless they are written to take this change into account.
Here is an example where RGB is the name of a radio control with options: R=red, G=blue, B=green. This rule triggers each time the user selects a new options. It finds the value and label of the selected option.
if (RGB.value.length > 0) {
for (x in RGB.options) {
var opt = RGB.options[x];
var val= opt.split('=')[0];
var lab= opt.split('=')[1];
if (RGB.value == val) {
V.value = val;
L.value = lab;
}
}
}
Refer to the select control options documentation for more information.
indexOf()
The JavaScript method indexOf() cannot be used in business rules in Live Forms v3.4.x. This will be fixed in the Live Forms v4. See the frevvo forum for a simple solution using the JavaScript split() method.












