Rules are probably best described by using examples. This chapter contains numerous real world samples.
...
Step 1 is named Expense Report, Step 2 is named Manager Approval and step 3 is named Accounting in the flow designer to match the sections in the parent form. The Manager role has been assigned to step 2 and the Accounting role has been assigned to step 3.
Here is an example of a rule that shows the Expense report details when the form loads, (the Manager Approval and Accounting sections are hidden) on step1, makes the Manager Approval section visible in the second step of the flow when performed by a manager and shows the Manager Approval and Accounting sections on step 3 when it is performed by an accounting department employee.
Code Block | ||
---|---|---|
| ||
if (form.load) { var an = _data.getParameter("flow.activity.name"); if (an === 'Manager Approval') { ManagerApproval.visible = true; } if (an === 'Accounting') { ManagerApproval.visible = true; Accounting.visible = true; } } |
Show/Hide Manager Approval on Step 2 and 3 of a flow
You have a flow and the first form has a Section for manager approval. The Section is hidden by default. Here is an example of a rule that makes the section visible in the second and third steps of the flow which are linked steps assigned to the manager and VP roles.
Code Block |
---|
if (form.load) { var an = _data.getParameter ("flow.activity.name"); if (an === 'Manager' || an === 'VP'){ ManagerApproval.visible = true; } else { ManagerApproval.visible = false; } } |
...
Code Block |
---|
Desc.status = 'Invalid. Max 20 chars allowed and you have ' + Desc.value.length; |
Textarea newline vs break
Users typically enter multi-line text into textarea controls. If you want to display that text in an html context, for example on a web page or in an html formatted email or in your form's Form Action display message you will need to replace newlines with html breaks. This caused by the fact that line breaks entered into a web form textarea are represented by a single newline character \n while line breaks in an html context are represented by the html break characters.
Our example has a textarea control named Description and a hidden control named DF. The user types into the visible control named Description and a business rules converts the newline characters \n into html breaks.
Code Block |
---|
var x = Description.value;
x = x.replace(/\\r/g,"");
x = x.replace(/\\n/g,"<br/>");
DF.value = x; |
Dropdown Options
This example automatically sets the option selected in one dropdown based on the option selected in another. This is often useful when you have a form with choices that were dynamically populated. For example, imagine product choices which are descriptive text. When the user selects a product, your form needs to perform an action based on a product ID rather than the descriptive product text. A nice way to do this is to have the rule that dynamically populates the product choices dropdown also populate a product ID dropdown which remains an invisible control in the form. The product choices dropdown control was named Products and the product ID dropdown control was named PID
The 1st rule "Load Products" populates both the visible and hidden dropdowns with options from a database.
...
Required Field Status in Accessible Forms
You can build forms/flows In that meet Section 508 and WCAG 2.0 accessibility standards. Accessible forms/flows can assist users with visual and motor impairments. When the Accessible property is enabled for a form/flow, the error, "You can't leave this empty <control name>" displays, if users move ahead from a required field without filling it. The status property for the empty control becomes invalid and sets the error message. Normally, the status property can be used in a business rule. For example, let's say a form has a text control named 't', and a message control named "m". If you write a rule to update the message field (control named m) with the STATUS of the required/invalid control (control named t), as shown below, it will not work because the "You can't leave this empty" message for a required control is not treated as it's status.
Code Block |
---|
if(!t.valid)
{
m.value = t.status;
} |
If the rule is written this way, it will fill the message control with the errmsg from the invalid text control.
Code Block |
---|
if (!t.valid) { if (t.value.length === 0) { m.value = "You if (x.resultSet[i]) {can't leave this empty." } else { opts1[i]m.value = x.resultSet[i].productNamet.status; opts2[i] = x.resultSet[i].productCode; } } Products.options = opts1; PID.options = opts2; Products.value = opts1[0]; // default to 1st product option PID.value = opts2[0]; } |
Finding a Selected Options Index
The 2nd rule Select Product ID keeps the hidden PID dropdown synchronized with the visible Products dropdown.
Code Block |
---|
if (Products.value.length > 0) { var i; for (var x in Products.options) { if ((Products.value + '=' + Products.value) === Products.options[x]){} } |
Textarea newline vs break
Users typically enter multi-line text into textarea controls. If you want to display that text in an html context, for example on a web page or in an html formatted email or in your form's Form Action display message you will need to replace newlines with html breaks. This caused by the fact that line breaks entered into a web form textarea are represented by a single newline character \n while line breaks in an html context are represented by the html break characters.
Our example has a textarea control named Description and a hidden control named DF. The user types into the visible control named Description and a business rules converts the newline characters \n into html breaks.
Code Block |
---|
var x = Description.value;
x = x.replace(/\\r/g,"");
x = x.replace(/\\n/g,"<br/>");
DF.value = x; |
Dropdown Options
This example automatically sets the option selected in one dropdown based on the option selected in another. This is often useful when you have a form with choices that were dynamically populated. For example, imagine product choices which are descriptive text. When the user selects a product, your form needs to perform an action based on a product ID rather than the descriptive product text. A nice way to do this is to have the rule that dynamically populates the product choices dropdown also populate a product ID dropdown which remains an invisible control in the form. The product choices dropdown control was named Products and the product ID dropdown control was named PID
The 1st rule "Load Products" populates both the visible and hidden dropdowns with options from a database.
Code Block |
---|
/*member productCode, productName, resultSet*/ var x; if (form.load) { eval('x=' + http.get('https://app.frevvo.com/database/BIRT/allProducts')); var opts1 = []; i = Products.options.indexOf(Products.options[x]); } } PID.value var opts2 = PID.options[i].split('=')[0]; } |
Rules using hidden dropdowns to keep descriptive option labels visible to the user while keeping cryptic database values hidden are often no longer necessary. Dropdown options have values distinct from the human visible option labels. The above can now be achieved with a single simpler rule:
Code Block |
---|
/*member description productId resultSet */ var x, opts1; for (var i=0; i < x.resultSet.length; i++) { if (x.resultSet[i]) { opts1[i] = x.resultSet[i].productId+ '=' + productName; opts2[i] = x.resultSet[i].descriptionproductCode; } } Rdocnum Products.options = opts1; |
Here is another rule that dynamically populates both the product choices and product ID dropdowns. This rule calls a REST Service which returns an object rather than the resultset returned by the database connector as shown above. See the section on dynamic content for more details.
Code Block |
---|
/*member ids products */ var x; if (S 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 synchronized with the visible Products dropdown.
Code Block |
---|
if (Products.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.
Code Block |
---|
var i, x;
for (x in Products.options) {
// Determine the index of the selected product in the Products dropdown options
if (Products.value === Products.options[x])
i = Products.options.indexOf(Products.options[x]);
}
// Changed the selected PID to match the selected Product
PID.value = PID.options[i] + ''; |
Clearing Dropdown Options
This sample resets a dropdown option to the automatically added blank option. For dropdowns added from palette controls and from schema, automatically adds a blank option so the dropdown initially shows no choice by default. To reset the dropdown, set the dropdown control's value to null not the empty string. The empty string will not work since the empty string is not a valid option. This form resets the dropdown named size whenever the value of the product option changes.
Code Block |
---|
if (product.value.length > 0) {
size.value = null;
} |
Default Option
When your options are set dynamically as shown below in a business rule, you cannot set a default in on the form designer. You need to set the default in the rule. If your options have <value>=<label> where value is different from label, make sure you set the <control>.value to <value> not <label> and not <value>=<label>
Code Block |
---|
if (form.load) {
var cc = ['R=Red', 'B=Blue', 'G=Green'];
Colors.options = cc;
Colors.value = 'B';
} |
Populating Dropdown Options from a Google Sheet
Dropdown control options can be dynamically populated from a Google Sheet using a business rule. Here is an example of a rule that populates a dropdown control named Colors with color options from a Google Sheet.
...
Create a Form with a control called Colors.
...
Use this rule to populate the dropdown options with the colors Red, Blue, Green and Orange. Note this rule uses http headers to provide authentication information and passes the Google sheet and worksheet names as query parameters. This is the recommended approach.
...
Replace <Google User ID> and <Google Account access token> with your information in the user and password headers.
...
var i;
for (var x in Products.options) {
if ((Products.value + '=' + Products.value) === Products.options[x]){
i = Products.options.indexOf(Products.options[x]);
}
}
PID.value = PID.options[i].split('=')[0];
} |
Rules using hidden dropdowns to keep descriptive option labels visible to the user while keeping cryptic database values hidden are often no longer necessary. Dropdown options have values distinct from the human visible option labels. The above can now be achieved with a single simpler rule:
Code Block |
---|
/*member description productId resultSet */
var x, opts1;
for (var i=0; i < x.resultSet.length; i++) {
if (x.resultSet[i]) {
opts1[i] = x.resultSet[i].productId+ '=' + x.resultSet[i].description;
}
}
Rdocnum.options = opts1; |
Here is another rule that dynamically populates both the product choices and product ID dropdowns. This rule calls a REST Service which returns an object rather than the resultset returned by the database connector as shown above. See the section on dynamic content for more details.
Code Block |
---|
/*member ids products */
var x;
if (S.value.length > 0) {
eval('x=' + http.get('http://localhost:8182/products/?category=' + 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.
Code Block |
---|
var i, x;
for (x in Products.options) {
// Determine the index of the selected product in the Products dropdown options
if (Products.value === Products.options[x])
i = Products.options.indexOf(Products.options[x]);
}
// Changed the selected PID to match the selected Product
PID.value = PID.options[i] + ''; |
Clearing Dropdown Options
This sample resets a dropdown option to the automatically added blank option. For dropdowns added from palette controls and from schema, automatically adds a blank option so the dropdown initially shows no choice by default. To reset the dropdown, set the dropdown control's value to null not the empty string. The empty string will not work since the empty string is not a valid option. This form resets the dropdown named size whenever the value of the product option changes.
Code Block |
---|
if (product.value.length > 0) {
size.value = null;
} |
Default Option
When your options are set dynamically as shown below in a business rule, you cannot set a default in on the form designer. You need to set the default in the rule. If your options have <value>=<label> where value is different from label, make sure you set the <control>.value to <value> not <label> and not <value>=<label>
Code Block |
---|
if (form.load) { var |
...
cc = ['R=Red', |
...
'B=Blue', 'G=Green']; Colors.options = cc; |
...
|
...
Colors.value = ' |
...
B';
} |
Populating Dropdown Options from a Google Sheet
Dropdown control options can be dynamically populated from a Google Sheet using a business rule. Here is an example of a rule that populates a dropdown control named Colors with color options from a Google Sheet.
- Create a Google Sheet with a column named Colors containing a list of colors.
Create a Form with a control called Colors.
Use this rule to populate the dropdown options with the colors Red, Blue, Green and Orange. Note this rule uses http headers to provide authentication information and passes the Google sheet and worksheet names as query parameters. This is the recommended approach.
Replace <Google User ID> and <Google Account access token> with your information in the user and password headers.
Change ssname= and wsname= to reflect the names of your Google sheet and worksheet.
Code Block |
---|
/*member colors, results */ var x; if (form.load) { var headers = '{"user":"<Google user Id>","password":"<Google Account access token>"}'; var readquery = '/google/spreadsheets/query?ssname=Colorlist&wsname=Sheet1'; eval('x=' + http.get(readquery,headers)); var opts = ['']; if (x.results) { for (var i = 0; i < x.results.length; i++) { if (x.results[i].colors) { var opts = ['']; if (x.results) { for (var i = 0; i < x.results.length; i++) { if (x.results[i].colors) { opts[i + 1] = x.results[i].colors; } } } Colors.options = opts; //Colors is the name of the dropdown control } |
Refer to this documentation for more information about and the Google Connector.
...
You can style this form so the comment input controls align with the checkbox options. See details and download a working sample form here.
Code Block |
---|
var heartProblem = false; var foodAllergy = false; var rashes = false; var jointInjury = false; var asthma = false; var moodiness = false; for (var i = 0; i < MedicalIssues.value.length; i++) { if (MedicalIssues[i].value === 'heart_problem') { heartProblem = true; } else if (MedicalIssues[i].value === 'food_allergy') { foodAllergy = true; } else if (MedicalIssues[i].value === 'rashes') { rashes = true; } else if (MedicalIssues[i].value === 'joint_injury') { jointInjury = true; } else if (MedicalIssues[i].value === 'asthma') { asthma = true; } else if (MedicalIssues[i].value === 'moodiness') { moodiness = true; } } if (heartProblem === true) { heartProblemDetails.visible = true; heartProblemDetails.required = true; } else { heartProblemDetails.visible = false; heartProblemDetails.required = false; //heartProblemDetails.value = null; } if (foodAllergy === true) { foodAllergyDetails.visible = true; foodAllergyDetails.required = true; } else { foodAllergyDetails.visible = false; foodAllergyDetails.required = false; //foodAllergyDetails.value = null; } if (rashes === true) { rashesDetails.visible = true; rashesDetails.required = true; } else { rashesDetails.visible = false; rashesDetails.required = false; //rashesDetails.value = null; } if (jointInjury === true) { jointInjuryDetails.visible = true; jointInjuryDetails.required = true; } else { jointInjuryDetails.visible = false; jointInjuryDetails.required = false; //jointInjuryDetails.value = null; } if (asthma === true) { asthmaDetails.visible = true; asthmaDetails.required = true; } else { asthmaDetails.visible = false; asthmaDetails.required = false; //asthmaDetails.value = null; } if (moodiness === true) { moodinessDetails.visible = true; moodinessDetails.required = true; } else { moodinessDetails.visible = false; moodinessDetails.required = false; //moodinessDetails.value = null; } |
...
This rule makes the appropriate input text controls visible depending on the choice a user makes in a radio option controls searchChoicecontrol searchChoice.
Code Block |
---|
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; } |
...
Warning |
---|
Rules initializing time and date/time controls will not work in a form.load rule unless you specify a timezone on the form's Url via the _formTz Url parameter. This is because the form server needs to know the timezone in which to return the date and time. If you do not specify a _formTz the methods will return null and the control values will remain blank. The timezone strings can be found here. For example, to specify Eastern time: &_formTz=America/NewYork. This URL parameter is not needed if your form/flow only contains Date controls. |
Age
This example form automatically determines today's date and then calculates the person's age in the control named 'Age' when they enter their birth date into the control named 'BirthDate'.
Code Block | ||
---|---|---|
| ||
if (BirthDate.value.length > 0) {
var today = new Date();
var dob = BirthDate can be found here. For example, to specify Eastern time: &_formTz=America/NewYork. This URL parameter is not needed if your form/flow only contains Date controls. |
Age
This example form automatically determines today's date and then calculates the person's age in the control named 'Age' when they enter their birth date into the control named 'BirthDate'.
Code Block | ||
---|---|---|
| ||
if (BirthDate.value.length > 0) {
var today = new Date();
var dob = BirthDate.value.split('-');
var dob2 = new Date(dob[0],dob[1]-1,dob[2]);
var age = today.getFullYear() - dob2.getFullYear();
if (today.getMonth() < dob2.getMonth() ||
(today.getMonth() === dob2.getMonth() &&
today.getDate() < dob2.getDate())) {
age -= 1;
}
if (age >= 0) {
Age.value = age;
} else {
Age.value = null;
}
} |
Duration
This form initializes the hospital discharge date using a rule, and when the user enters the admission date a 2nd rule calculates the number of days the patient stayed in the hospital.
Code Block | ||
---|---|---|
| ||
/ Calculate Hospital Stay Duration if (A.value !== '' && D.value !== '') { var da = A.value.split('-'); var Ams = new Date(da[0],da[1],da[2]); da = D.value.split('-'); var dob2Dms = new Date(dobda[0],dobda[1]-1,dobda[2]); var age =if today.getFullYear() - dob2.getFullYear(); if (today.getMonth() < dob2.getMonth() ||(Ams > Dms) { Days.value = 'Discharge date must be after Admission Date'; } (today.getMonth() === dob2.getMonth() &&else { today.getDate() < dob2.getDate())) { age -= 1; } if (age >= 0) { Age.value = age; } else { Age.value = null; } } |
Duration
This form initializes the hospital discharge date using a rule, and when the user enters the admission date a 2nd rule calculates the number of days the patient stayed in the hospital.
Code Block | ||
---|---|---|
| ||
/ Calculate Hospital Stay Duration if (A.value !== '' && D.value !== '') { Days.value = (Dms - Ams) / (1000*60*60*24) + ' days'; } } |
Duration (between Date/Time)
Here is a rule example to calculate the time difference between two Date/Time values in hours:minutes format :
Code Block |
---|
if (StartDateTime.value !== '' && EndDateTime.value !== '') { var d = StartDateTime.value.split('-'); var d1 = d[2].split('T'); var t = d1[1].split('Z')[0]; var dat1 = At.value.split('-:'); var AmsstartDate = new Date(dad[0],d[1],d1[0], t1[0],da t1[1],da t1[2]); da d = DEndDateTime.value.split('-'); var Dmsd1 = new Date(da[0],da[1],dad[2].split('T'); t if (Ams > Dms) { = d1[1].split('Z')[0]; var t1 = t.split(':'); var Days.valueendDate = 'Discharge date must be after Admission Date'new Date(d[0],d[1],d1[0], t1[0], t1[1], t1[2]); } elsevar {diff = endDate.getTime() - startDate.getTime(); var Days.valuehours = Math.floor(Dmsdiff -/ Ams)1000 / (1000*60*60*24) + ' days'60 / 60); diff } } |
Duration (between Date/Time)
Here is a rule example to calculate the time difference between two Date/Time values in hours:minutes format :
Code Block |
---|
if (StartDateTime.value !== '' && EndDateTime.value !== '') { var d = StartDateTime.value.split('-'); var d1 = d[2].split('T'-= hours * 1000 * 60 * 60; var minutes = Math.floor(diff / 1000 / 60); var tTimeToComplete.value = d1[1].split('Z')[0]; var t1 = t.split(':'); var startDate = new Date(d[0],d[1],d1[0], t1[0], t1[1], t1[2]); d = EndDateTime.value.split('-'); d1 = d[2].split('T'); t = d1[1].split('Z')[0]; var t1 = t.split(':'); var endDate = new Date(d[0],d[1],d1[0], t1[0], t1[1], t1[2]); var diff = endDate.getTime() - startDate.getTime(); var hours = Math.floor(diff / 1000 / 60 / 60); diff -= hours * 1000 * 60 * 60; var minutes = Math.floor(diff / 1000 / 60); TimeToComplete.value = (hours < 9 ? "0" : "") + hours + ":" + (minutes < 9 ? "0" : "") + minutes; } |
Today's Date and Time
Use ' built-in date and time methods to set your date, time, and date/time controls to the current date and time in the user's local timezone.
Code Block |
---|
if (form.load) {
Tm.value = frevvo.currentTime();
Dt.value = frevvo.currentDate();
DtTm.value = frevvo.currentDateTime();
} |
Note |
---|
The currentTime(), currentDate() and currentDateTime() will not work in a form.load rule unless you specify a timezone on the form's Url via the _formTz Url parameter. This is because the form server needs to know the timezone in which to return the date and time. If you do not specify a formTz the methods will return null and the control values will remain blank. For example &formTz=America/New_York will set the control values to the current date and time in the eastern timezone. |
Date/Time Stamp
This rule sets a control named Signature to the value of a control named Name plus a date/time stamp. Note that it is better to use the built-in date and time methods if you want to set the date to the user's local timezone. The following method will set the date to the form server's timezone.
Code Block | ||
---|---|---|
| ||
var today=new Date();
var m = today.getMonth() + 1;
var d = today.getDate();
var y = today.getFullYear();
var h = today.getHours(); var min = today.getMinutes(); var todayStr = m + '-' + d + '-' + y + ' ' + h + ':' + min; Signature.value = 'Signed by ' + Name.value + ' on ' + todayStr; |
Invalid if Before Today
This rule makes the date control invalid if the date entered isn't before today's date.
Code Block |
---|
// frevvo currentDate method gets today in users timezone var today = frevvo.currentDate().split('-'); var today_date = new Date(today[0], today[1]-1, today[2]); var bd = DOB.value.split('-'); var bd_date = new Date(bd[0],bd[1]-1,bd[2]); if (bd_date > today_date(hours < 9 ? "0" : "") + hours + ":" + (minutes < 9 ? "0" : "") + minutes; } |
Today's Date and Time
Use ' built-in date and time methods to set your date, time, and date/time controls to the current date and time in the user's local timezone.
Code Block |
---|
if (form.load) {
Tm.value = frevvo.currentTime();
Dt.value = frevvo.currentDate();
DtTm.value = frevvo.currentDateTime();
} |
Note |
---|
The currentTime(), currentDate() and currentDateTime() will not work in a form.load rule unless you specify a timezone on the form's Url via the _formTz Url parameter. This is because the form server needs to know the timezone in which to return the date and time. If you do not specify a formTz the methods will return null and the control values will remain blank. For example &formTz=America/New_York will set the control values to the current date and time in the eastern timezone. |
Date/Time Stamp
This rule sets a control named Signature to the value of a control named Name plus a date/time stamp. Note that it is better to use the built-in date and time methods if you want to set the date to the user's local timezone. The following method will set the date to the form server's timezone.
Code Block | ||
---|---|---|
| ||
var today=new Date();
var m = today.getMonth() + 1;
var d = today.getDate();
var y = today.getFullYear();
var h = today.getHours(); var min = today.getMinutes(); var todayStr = m + '-' + d + '-' + y + ' ' + h + ':' + min; Signature.value = 'Signed by ' + Name.value + ' on ' + todayStr; |
Invalid if Before Today
This rule makes the date control invalid if the date entered isn't before today's date.
Code Block |
---|
// frevvo currentDate method gets today in users timezone
var today = frevvo.currentDate().split('-');
var today_date = new Date(today[0], today[1]-1, today[2]);
var bd = DOB.value.split('-');
var bd_date = new Date(bd[0],bd[1]-1,bd[2]);
if (bd_date > today_date) {
MyMsg.value = 'Birth Date must be earlier than today!!!!';
DOB.valid = false;
} else {
MyMsg.value = 'This is a good Birth Date: ' + DOB.value;
DOB.valid = true;
} |
Note |
---|
Use frevvo.currentDate() rather than the javascript new Date() since the latter gets today's date in the Live Forms server's timezone while the frevvo currentDate() correctly gets today's date in the user's timezone. |
Date no more then 14 days from Today
This rule checks that the date entered into a control named AppointmentDate is no more than 14 days greater than today's date.
Code Block |
---|
var date1 = DateUtil.today(); var date2 = Appointment.value; date1 = date1.split("-"); date2 = date2.split("-"); var sDate = new Date(date1[0]+"/"+date1[1]+"/"+date1[2]); var eDate = new Date(date2[0]+"/"+date2[1]+"/"+date2[2]); var DaysApart = Math.round((eDate-sDate)/86400000); if (DaysApart > 14) { MyMsgAppointment.valuestatus = 'Birth "Date mustshould be earlier thanwithin 14 days from today!!!!'; DOB.valid = falses date."; } else {if (DaysApart < 0) { MyMsg.value = 'This is a good Birth Date: ' + DOB.value; DOB.valid = true; } |
Note |
Use frevvo.currentDate() rather than the javascript new Date() since the latter gets today's date in the Live Forms server's timezone while the frevvo currentDate() correctly gets today's date in the user's timezone. Appointment.status = "Date should not be earlier to today's date.";
} |
Date no more then
...
30 days
...
ago
This rule checks that the date entered into a control named AppointmentDate is no more than 14 days greater than today's dateEventStartDate is not more then 30 days ago.
Code Block |
---|
if (EventStartDate.value !== "") { var date1 = DateUtil.today(); var date2 = AppointmentEventStartDate.value; date1 = date1.split("-"); date2 = date2.split("-"); var sDate = new Date(date1[0]+"/"+date1[1]+"/"+date1[2]); var eDate = new Date(date2[0]+"/"+date2[1]+"/"+date2[2]); var DaysApartdays = Math.round((eDate-sDate)/86400000); if (DaysApart!eval(parseInt(days,10) > 14parseInt(-30,10))) { EventStartDate.valid = false; Appointment EventStartDate.status = "Date should be within 14 days from today's dateThe date entered can only go back a maximum of 30 days from the current date. Please try again."; } else if (DaysApart < 0) { AppointmentEventStartDate.statusvalid = "Date should not be earlier to today's date."true; } } |
Date no more then 30 days ago
This rule checks that the date entered into a control named EventStartDate is not more then 30 days ago.
Code Block |
---|
if (EventStartDate.value !== "") {
var date1 = DateUtil.today();
var date2 = EventStartDate.value;
date1 = date1.split("-");
date2 = date2.split("-");
var sDate = new Date(date1[0]+"/"+date1[1]+"/"+date1[2]);
var eDate = new Date(date2[0]+"/"+date2[1]+"/"+date2[2]);
var days = Math.round((eDate-sDate)/86400000);
if (!eval(parseInt(days,10) > parseInt(-30,10))) {
EventStartDate.valid = false;
EventStartDate.status = "The date entered can only go back a maximum of 30 days from the current date. Please try again.";
} else {
EventStartDate.valid = true;
}
} |
Add Years, Months or Days to a Date
Here is a rule that will add 3 years to a given date. For example, to calculate the expiration date of a three year contract by adding three years to the starting date, your form could have two date controls, one used to enter the starting date and the other to show the contract expiration date. This rule will take the date from the StartingDate field, add 3 years to it and populate the result in a field named ExpirationDate.
...
Add Years, Months or Days to a Date
Here is a rule that will add 3 years to a given date. For example, to calculate the expiration date of a three year contract by adding three years to the starting date, your form could have two date controls, one used to enter the starting date and the other to show the contract expiration date. This rule will take the date from the StartingDate field, add 3 years to it and populate the result in a field named ExpirationDate.
Code Block |
---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate.value = frevvo.addToDate(dt,'y','3');
} |
This rule adds 1 month to the Start Date:
Code Block |
---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate.value = frevvo.addToDate(dt,'m','1');
} |
This rule adds 11 days to the Start Date:
Code Block |
---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate.value = frevvo.addToDate(dt,'d','11');
} |
These functions can be used with Date and Date/Time controls.
Setting a Future Date
You can write a rule using the addToDate method to calculate a future date. The example code executes when the form loads. It uses the DateUtil.today() method to populate the control named D1 with the current date. This method returns today's date in the format 'yyyy-mm-dd' instead of 'mm-dd-yyyy', making it compatible with utility methods such as addToDate(). The rule then
- adds one month to the current date to populate the control named D2.
- adds one day to the current date to populate the control named D3.
- adds one year to the current date to populate the control named D3.
Column |
---|
Column | |||||||
---|---|---|---|---|---|---|---|
|
This rule adds 1 month to the Start Date:
Code Block | ||
---|---|---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate.value
|
This rule adds 11 days to the Start Date:
Code Block | |||
---|---|---|---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate.value
|
These functions can be used with Date and Date/Time controls.
Calculate a Date based on a five day work week
You may want to calculate a date in a workflow based on a five day work week. This is a common business scenario and may be helpful if you are using the Escalations feature. It is not possible to select calendar or working days for the Days interval of the Escalation feature at this time but this enhancement is planned for a future release. As a work-around, you can calculate X number of working days from the current date, and set that date in a Date control on your form. Then while configuring escalations, use the ‘Complete By’ condition and select the Date control.
Here is the business function/rule that will add 3 working days to the current date to give you the escalation date. Copy/paste the entire rule including the function in the Rule Editor. Substitute the name of your date control for <your date control>:
Code Block | ||
---|---|---|
| ||
function calcWorkingDays(fromDate, days) { var count = 0; while (count < days) { fromDate.setDate(fromDate.getDate() + 1); if (fromDate.getDay() !== 0 && fromDate.getDay() !== 6) { // Skip weekends count++; } } return fromDate; } if (form.load && <your date control>.value.length === 0){ var numWorkingDays = 3; var today = frevvo.currentDate().split('-'); var escDate = calcWorkingDays(new Date(today[0], today[1]-1, today[2]), numWorkingDays); var m = escDate.getMonth() + 1; var d = escDate.getDate(); var y = escDate.getFullYear(); <your date control>.value = m + '-' + d + '-' + y; } |
...
Note |
---|
Use this example only when you want to add whole number hours. Adding a decimal value for the time interval (such as 7.5) will not work. |
...
Displaying Dates in Message Controls
Irrespective of your date control's Date Format, the server stores that value in a connical yyyy-dd-mm format. Thus the Date Format affects only the format the user sees while using the form and not the actual stored value. The connical format is also what you will see in your form's submission XML. When you want to use a date control's value in a message control you will need to convert the connical date format to your desired display format. This rule writes the date control named datefield into a message control named Msg using the format dd/mm/yyyy.
...
format. This rule writes the date control named datefield into a message control named Msg using the format dd/mm/yyyy.
Code Block |
---|
var date = datefield.value.split('-');
var dateStr = date[2] + '/' + date[1] + '/' + date[0] ;
Msg.value = "I selected the date: " + dateStr; |
Checking a Date for Extra Digits
This rule uses the valid property to verify that the entered date does contain extra digits. For example, if a user enters a date with a 6 digit year (1/2/201717) into a control named StartDate, the customized error message displays.
Code Block | ||
---|---|---|
| ||
if (StartDate.value.length > 10) {
StartDate.valid = false;
StartDate.status = 'Invalid. Please check that the date is entered in the mm-dd-yyyy format';
} else {
StartDate.valid = true;
} |
Times
The date control can be set to either just a date, just a time, or a combined date/time. Here are several examples of initializing a time control named Tm;
...
Code Block | ||
---|---|---|
| ||
if(count.value > 0){ if(TableRepeat.maxOccurs < count.value) { TableRepeat.maxOccurs = count.value; TableRepeat.minOccurs = count.value; Repeat.maxOccurs = count.value; Repeat.minOccurs = count.value; } else{ TableRepeat.minOccurs = count.value; TableRepeat.maxOccurs = count.value; Repeat.minOccurs = count.value; Repeat.maxOccurs = count.value; } } |
Notice the rule flips the order of minOccurs and maxOccurs in the if and else blocks so that at a given point minOccurs is not set to something greater than maxOccurs and maxOccurs is not set to something less than minOccurs.
For example, when you set the count to 6, the rule executes and sets minOccurs and maxOccurs values to 6. Now if you change the count to 3, then you will have to first set minOccurs to 3 (because it should never be greater than maxOccurs), and then change the maxOccurs to 3. Then if you change the count to 8, you have to first set maxOccurs to 8 (because it should never be less than minOccurs), and then set minOccurs to 8.
Entering "5" as the number of travelers, sets the minOccurs and maxOccurs to 5 and shows 5 information sections and 5 rows in the table. Note the plus and minus icons are not visible preventing users from adding or removing repeat items or table rows,
...
Let's take a look at a simple example. Users are instructed to enter a capital Y in a table if they are planning on calling a customer. The user enters the "Y" then tabs to the company name column. The minus icon for that row will disappear. minus icon for that row will disappear.
In this example, the name of the table control is CustomerTable and column 0 in the table is named ContactCustomer.
Here is the rule:
Code Block |
---|
for (var i=0; i<ContactCustomer.value.length; i++) { if (ContactCustomer[i].value === "Y") { CustomerTableItem[i].deletable = false; } else { CustomerTableItem[i].deletable = true; } } |
Notice the TableItem deletable property is set to false when a capital Y is entered in the first column. This will remove the minus icon for that row of the table. The for loop cycles through the table rows until the Max# property is reached.
Clearing Values in a Table
This rule clears the values from all rows in a table. Notice the For loop that iterates over all the rows. Inside the loop a null value is assigned to all the columns in the table row.
Code Block | ||
---|---|---|
| ||
for (var i = 0; i < Col0.value.length; i++) {
Col0[i].value = null;
Col1[i].value = null;
Col2[i].value = null;
} |
You cannot clear an entire table from a rule.
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 form.load are triggered when a form first loads and when a workflow is loaded from a task list.
...
A rule can dynamically display an image uploaded to your form via the upload control. In this example the upload control is named 'u'. The form also must contain a message control as a place holder for displaying the uploaded image. The rule dynamically creates a URL to the uploaded image in the temporary attachment repository. The upload control's value 'u.value' is a GUID that uniquely identifies the attachment. The uploaded image will be included in the submission PDF.
Code Block | ||
---|---|---|
| ||
if (u.value.length > 0) { var baseUrl = "/frevvo/web/tn/" + _data.getParameter('tn.id') + "/user/"+_data.getParameter('user.id') + "/app/"+_data.getParameter('app.id') + "/form/"+_data.getParameter('form.id'); im.value = '<img src="' + baseUrl + '/attachment/' + u.value+'/does_not_matter"/>'; } |
...