Creating JavaScript Form Controls (Advanced)
  • Updated on 20 Feb 2017
  • 4 minutes to read
  • Print
  • Dark
    Light

Creating JavaScript Form Controls (Advanced)

  • Print
  • Dark
    Light

This document applies only to 5.0 versions.
The first part of this documentation showed the basics of creating & using JS controls. Now we'll look at how to create a control that takes input data, and how to add CSS styles to a control.
This time, our example will be slightly different:
The control will consist of two buttons:  a 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:  You'll be able 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).
Let's take another look at the JS data control interface that we'll be implementing:

 interface JSBasedComponentInterface {
    initialize(host: JQuery, component: any): void;
    resize(height: number, width: number): void;
    setValue?(data: any): void;
    getValue?(): any;
  }

We'll start with a blank text document and name our control class 'MyResetButtonControl'. Our `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 our control with this function - it's called during form initialization and every time the input data changes. Let's say that our 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.
Instructions for creating the new form control can be found in the first part of this documentation . Just make sure that the Input Data section has the correct info, in addition to the Output Data section:
2018-01-09_125326-1.png

Was this article helpful?