- 23 Dec 2020
- 4 Minutes to read
- Print
- DarkLight
Creating JavaScript Form Controls (Advanced)
- Updated on 23 Dec 2020
- 4 Minutes to read
- Print
- DarkLight
Overview
This article demonstrates how to create a Form Control that receives an input and how to add CSS to the Control. For a basic overview of this topic, please visit the Creating Javascript Form Controls article.
Example
In this example, the control will consist of two buttons: the main button, which increases the click count, and a reset button, which sets the click count back to zero. It'll output two pieces of data: The current click count (since the reset button was clicked), and the total click count (which isn't affected by the reset button).
This control will also have two inputs: the ability to set the text on the main button, and also provide a starting count (in case you want to start counting at a number other than zero)
Take another look at the JS data control interface that will be implemented:
interface JSBasedComponentInterface {
initialize(host: JQuery, component: any): void;
resize(height: number, width: number): void;
setValue(data: any): void;
getValue(): any;
}
Start with a blank text document and name the control class 'MyResetButtonControl'. The initialize
function looks like this:
MyResetButtonControl.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');
var button = document.createElement('button');
button.classList.add('myControlButton');
button.type = 'button';
button.textContent = 'Click me';
var thisControl = this; // To avoid 'this' problems inside the onclick event.
button.onclick = function(e){
thisControl.currentCount++;
thisControl.totalCount++;
};
control.appendChild(button);
var resetButton = document.createElement('button');
resetButton.classList.add('myControlButton');
resetButton.type = 'button';
resetButton.textContent = 'Reset';
resetButton.onclick = function(e){
if(thisControl.currentCount > 0){
thisControl.currentCount = 0;
}
};
control.appendChild(resetButton);
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; }';
document.head.appendChild(style);
};
The resize
function is unchanged, so once again we copy & paste it:
MyResetButtonControl.prototype.resize = function(height, width) {
if (this.host && height && width && (height > 0) && (width > 0)) {
this.host.css({ width: width, height: height });
}
};
Next is setValue
. Input data is sent into the control with this function - it's called during form initialization and every time the input data changes.
Let's say that the inputs are 'StartingCount' and 'ButtonText':
MyResetButtonControl.prototype.setValue = function(data) {
// The lastConsumed variable, declared in 'initialize', is used to track changes in
// input data. If data exists, we make sure it has changed since last time:
if(data && JSON.stringify(data) !== JSON.stringify(this.lastConsumed)){
// Proceed only if the data is different than last time:
this.lastConsumed = data;
// Here, we treat StartingCount as optional, by using a value of 0 if no value
// was given:
var startingCount = data.StartingCount || 0;
this.currentCount = startingCount;
this.totalCount = startingCount;
// We've decided that ButtonText should also be an optional input,
// so check whether it exists before using it. (If the ButtonText input is
// set to Ignore, we'll keep the default button text, 'Click me'.)
if(data.ButtonText){
// Use JQuery's find function to find the first button on our control:
this.host.find('button')[0].textContent = data.ButtonText;
}
}
};
Finally, getValue
now returns 2 values in its output data:
MyResetButtonControl.prototype.getValue = function() {
return {
CurrentClickCount: this.currentCount,
TotalClickCount: this.totalCount
};
};
Putting it all together:
function MyResetButtonControl() { };
MyResetButtonControl.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');
var button = document.createElement('button');
button.classList.add('myControlButton');
button.type = 'button';
button.textContent = 'Click me';
var thisControl = this; // To avoid 'this' problems inside the onclick event.
button.onclick = function(e){
thisControl.currentCount++;
thisControl.totalCount++;
};
control.appendChild(button);
var resetButton = document.createElement('button');
resetButton.classList.add('myControlButton');
resetButton.type = 'button';
resetButton.textContent = 'Reset';
resetButton.onclick = function(e){
if(thisControl.currentCount > 0){
thisControl.currentCount = 0;
}
};
control.appendChild(resetButton);
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; }';
document.head.appendChild(style);
};
MyResetButtonControl.prototype.resize = function(height, width) {
if (this.host && height && width && (height > 0) && (width > 0)) {
this.host.css({ width: width, height: height });
}
};
MyResetButtonControl.prototype.setValue = function(data) {
// The lastConsumed variable, declared in 'initialize', is used to track changes in
// input data. If data exists, we make sure it has changed since last time:
if(data && JSON.stringify(data) !== JSON.stringify(this.lastConsumed)){
// Proceed only if the data is different than last time:
this.lastConsumed = data;
// Here, we treat StartingCount as optional, by using a value of 0 if no value
// was given:
var startingCount = data.StartingCount || 0;
this.currentCount = startingCount;
this.totalCount = startingCount;
// We've decided that ButtonText should also be an optional input,
// so check whether it exists before using it. (If the ButtonText input is
// set to Ignore, we'll keep the default button text, 'Click me'.)
if(data.ButtonText){
// Use JQuery's find function to find the first button on our control:
this.host.find('button')[0].textContent = data.ButtonText;
}
}
};
MyResetButtonControl.prototype.getValue = function() {
return {
CurrentClickCount: this.currentCount,
TotalClickCount: this.totalCount
};
};
Save as MyJsResetControl.js, and it's ready to be added as a new form control.
Just make sure that the Input Data section has the correct info, in addition to the Output Data section.