- 04 Aug 2022
- 7 Minutes to read
-
Print
-
DarkLight
Creating JavaScript Form Controls
- Updated on 04 Aug 2022
- 7 Minutes to read
-
Print
-
DarkLight
Users may build their own custom Form controls with JavaScript (JS) to use within the platform. Similar to built-in controls, JS controls also contain inputs and outputs. The process for configuring each of these JS controls is primarily the same. For Action, Data, and Page controls, a JS file will need to be uploaded and have its Class name declared in Decisions. Scripts and Style JS controls only need to have the JS files uploaded.
Below is a brief explanation of the different control types.
Control Type | Function |
---|---|
Action Control | Action Controls are Form Controls to trigger actions, i.e., Button, Link. |
Data Control | This is a Form Control that allows users to work with Data like JS Data Grids or Text Boxes. |
Page Control | These are Page Controls which are custom JS components that are used in the Dashboard/Page Designer. |
Scripts | This feature allows users to include Custom Scripts to upload JS Controls. |
Styles | This feature allows users to include Custom Styles (CSS) to upload JS Controls. |
Troubleshooting JS Controls
To troubleshoot JS controls, chrome developer tools will need to be used. This can be accessed by pressing F12 on the keyboard and navigating to the 'Network' tab to verify the JS control is running. Another troubleshooting step would be to empty the cache and reload it to ensure the cache is empty.Creating the Control
Start by creating a very simple control. This example will be a Decisions Data Control. It will consist of a single button, and the control output will be the number of times the button has been clicked. The control won't need any input data.
All JavaScript data controls will have these 4 specific functions:
interface JSBasedComponentInterface {
initialize(host: JQuery, component: any): void;
resize(height: number, width: number): void;
setValue?(data: any): void;
getValue?(): any;
}
Functions | Purpose |
---|---|
initialize | This function will be called one time when the control is being created. |
This function can handle special resizing rules, but most controls won't need to modify it - copying & pasting this 'resize' function should suffice when necessary. | |
setValue | This function is used when control takes input data. For an example that includes input data, see the Creating JavaScript Controls (Advanced) for this feature. |
getValue | This is where the output will be returned. |
Start with a blank text document. Name the control class 'MyControl':
function MyControl() { };
The first function to add is 'initialize.' This function will be called one time when the control is being created.
MyControl.prototype.initialize = function(host, component){
// Here we assign 'host' to a variable on this control,
// so that we can access it later:
this.host = host;
// Our counter starts at 0:
this.timesClicked = 0;
// Create and configure the button:
var button = document.createElement('button');
button.type = 'button';
button.textContent = 'Click me';
var thisControl = this; // To avoid 'this' problems inside the onclick event.
// When the button is clicked, increment our counter:
button.onclick = function(e){
thisControl.timesClicked++;
};
// Add the button to the 'host' jquery object:
host.append(button);
};
The next function in the class is 'resize.'
MyControl.prototype.resize = function(height, width) {
if (this.host && height && width && (height > 0) && (width > 0)) {
this.host.css({ width: width, height: height });
}
};
This function can handle special resizing rules, but most controls won't need to modify it - copying & pasting this 'resize' function should suffice when necessary.
Next is 'setValue'. This function is used when control takes input data. However, this control has no inputs; the 'setValue' function will remain empty.
MyControl.prototype.setValue = function(data){
// This control has no inputs, so no code is necessary here.
};
Finally, add 'getValue'. This is where the output will be returned. This function will be called once when the form concludes.
MyControl.prototype.getValue = function() {
// Output data should be an object with properties that match the
// names of our outputs. In this case, our output is named 'TimesClicked'.
return {
TimesClicked: this.timesClicked
};
};
The completed JavaScript control will look like the screenshot below. Save this as MyControl.js, and then load it into Decisions.
function MyControl() { };
MyControl.prototype.initialize = function(host, component){
// Here we assign 'host' to a variable on this control,
// so that we can access it later:
this.host = host;
// Our counter starts at 0:
this.timesClicked = 0;
// Create and configure the button:
var button = document.createElement('button');
button.type = 'button';
button.textContent = 'Click me';
var thisControl = this; // To avoid 'this' problems inside the onclick event.
// When the button is clicked, increment our counter:
button.onclick = function(e){
thisControl.timesClicked++;
};
// Add the button to the 'host' jquery object:
host.append(button);
};
MyControl.prototype.resize = function(height, width) {
if (this.host && height && width && (height > 0) && (width > 0)) {
this.host.css({ width: width, height: height });
}
};
MyControl.prototype.setValue = function(data){
// This control has no inputs, so no code is necessary here.
};
MyControl.prototype.getValue = function() {
// Output data should be an object with properties that match the
// names of our outputs. In this case, our output is named 'TimesClicked'.
return {
TimesClicked: this.timesClicked
};
};
Loading a .js file into Decisions as a JS form control
Navigate to a Designer Folder. Select the 'Create Form' button, find the JavaScript Control menu, select Add Data Control, then select 'Create'.
In the Add Javascript Control window, give the control a name.
This control has no input data. Therefore, nothing needs to be added to the Input Data section.
Define output data by selecting the Different Output Data checkbox, then the Output Data section will appear.
Select Add New under the Output Data section. The control has a numerical output named "TimesClicked". In the Name field type "TimesClicked", and pick Int32 [Number] for the Type field, then select 'Ok'.
In the Runtime Information section, the JS Class Name must match the class name inside the .js file. The class name is 'MyControl', type MyControl in the JS Class Name field. Select Choose File to upload the MyControl.js file.
Select 'Save Control' to create the new Form Control.
Using a JS control in a form
Create a new Form. In the Form Controls tab at the upper right, start by dragging a Button onto the form. Name it 'Submit'.
Next, in the Form Controls > JS Controls > [Current Folder] drag the JS Control to the form. Save and close the Form Designer.
Next, create a Flow to display the form. Add a Show Form step, and select the Form that was just created. Select Debug in the top action panel.
Select the 'Click me' button many times, then select Submit.
Select the Show Form step, and then select View Output Data. Notice that the output from the Form includes the TimesClicked.
Creating An Action Control
This example will demonstrate a JS Action Control. The following JavaScript code and the file it is located in will be used for illustration.
function ListButtonControl() { };
ListButtonControl.prototype.initialize = function(host, component) {
// Keep track of the host; we'll need it later.
this.host = host;
// Initialize our count data:
this.currentCount = 0;
this.totalCount = 0;
// This one is important when we have input data. See 'consumeData' for details.
this.lastConsumed = null;
// We're going to put both buttons in a div, then append the div to the host:
var control = document.createElement('div');
// Loop through all possible outcome names.
for (var outcome of component.PossibleOutcomeNames) {
// create button element
var button = document.createElement('button');
// add class
button.classList.add('myControlButton');
button.type = 'button';
// set the text same as outcome name
button.textContent = outcome;
var thisControl = this; // To avoid 'this' problems inside the onclick event.
button.onclick = function(e){
// to submit the form when button is clicked, selectPath should be called with correct outcome name
// the outcome here should be from possibleOutcome names that we define while creating the JS action control
// otherwise the flow will throw an error.
component.selectPath(this.textContent);
};
control.appendChild(button);
}
host.append(control);
// The two buttons appear too close together unless we add some css:
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.myControlButton{ margin: 5px; height: 30px; color: #fff;background-color: #007bff;border-color: #007bff;border: 1px solid transparent;padding: .375rem .75rem;font-size: 1rem;line-height: 1.5; }';
document.head.appendChild(style);
};
ListButtonControl.prototype.resize = function(height, width) {
if (this.host && height && width && (height > 0) && (width > 0)) {
this.host.css({ width: width, height: height });
}
};
After downloading the JS file, open Decisions and click 'Create Form' -> 'Java Script Control' -> 'Add Action Control.
Next, give the JS Control a name, and set the 'Possible Outcome Paths' to: 'Submit', 'Cancel', and 'Reset'.
Then declare the 'JS Class name' to "ListButtonControl"
Once the JS Control has been uploaded, create a new form to apply the JS Control to that newly created form.
Finally, add the Form to a Flow and debug the Flow. Notice that the JS Action Control Button list behaves like a normal button in Decisions. Depending on the button clicked, the Flow will take that outcome path.