Smiley Custom Control

Here we will demonstrate and explain a very simple demo of building a custom IntraWeb control. This is not an exhaustive demo, but instead serves to show the basics of creating a custom IntraWeb control for use in IWML.

Hello Smiley

The custom control is a very simple control that uses a button and based on a boolean property displays a simple text based emoji of a happy or sad face.

Despite this being a simple control, all IntraWeb controls from a simple text control to the JQueryUI controls are all developed using the very same API demonstrated here.

Smiley Lives

A simple demo of the smiley control. 

View source code for this demo

Smiley Deconstructed

In it most raw form we need to implement 2 methods to create a custom control.

namespace IntraWeb.Controls.SmileyControl {
  export class Smiley extends IntraWeb.Control {
    protected _Button: HTMLButtonElement = null;

    public readonly IsHappy = this.BoolProp(true);

    protected InitDOM(): void {
      this._Button = IntraWeb.New.Button();
      this.SetDomRoot(this._Button);
    }

    protected Render(): void {
      super.Render();
      this._Button.innerHTML = this.IsHappy.IsTrue ? ":)" : ":(";
    }
  }
}

Note the property syntax. JavaScript lacks a reflection and practically proper type system so properties are themselves classes that support extra functionality necessary to streaming and other functions.

This code alone is enough to implement Smiley. Now Smiley can be used in an IWML file using the tag SmileyControl.Smiley.

SmileyControl
  IsHappy: true
]

IsHappy defaults to true so it does not need to be specified in this case, but we only have one property so it has been included in the example for demonstration purposes.

Pick a Namespace

Custom controls must exist in a namespace, but a single namespace can contain several controls although for Smiley we have only one.

namespace IntraWeb.Controls.SmileyControl {

The namespace must be a sub namespace of IntraWeb.Control. Normally the namespace would be the name of the control pack, a vendor name, or other. In this example we have chosen SmileyControl. This is not the name of the control itself, only the namespace that it belongs to. The namespace should be short, but unique. If Atozed developed custom controls as a third party vendor, Atozed would probably be used making the full namespace IntraWeb.Controls.Atozed.

The name of the containing source unit must also match the namespace. In this example, it means that Smiley exists in SmileyControl.ts and SmileyControl.js when compiled. The namespace and source file name must match if the control is to be auto loaded. If they do not match, the source file must be manually loaded.

Declare a New Class

Next we define the actual control itself.

export class Smiley extends IntraWeb.Control {

The class must inherit from (extend keyword) IntraWeb.Control or one of its descendants like IntraWeb.FocusControl or IntraWeb.InputControl. As this is a simple control, we are using just IntraWeb.Control.

The class must also be marked with the export keyword to be visible to IntraWeb. Without the export keyword, Smiley will not be usable from IWML.

InitDOM Method

Every component needs a root HTML element. Controls can have many HTML elements, but in such cases there still must be one root element that contains the other elements. IntraWeb uses this root element to control visibility, layout, placement and more within the browser DOM.

Every InitDOM method at a minimum must call SetDomRoot and pass in a HTML element. In the case of Smiley we create a button and pass it. We also store it in this._Button. This is not required, but saves us from needing to typecast this.DomRoot (not used in Smiley, but exists in IntraWeb.Control) each time we access it in .Render.

protected _Button: HTMLButtonElement = null;

protected InitDOM(): void {
  this._Button = IntraWeb.New.Button();
  this.SetDomRoot(this._Button);
}

Every InitDOM method at a minimum must call SetDomRoot and pass in a HTML element. In the case of Smiley we create a button and pass it.

We also store it in this._Button. This is not required, but saves us from needing to typecast this.DomRoot (not used in Smiley, but exists in IntraWeb.Control) each time we access it in .Render.

Render Method

InitDOM is called only once for each instance of a control and is not called until the first rendering. After that, Render is called for each render to update changes from the control to the DOM.

public readonly IsHappy = this.BoolProp(true);

protected Render(): void {
  super.Render();
  this._Button.innerHTML = this.IsHappy.IsTrue ? ":)" : ":(";
}

In this example, the only thing that needs to change is the innerHTML based on IsHappy.

Ready to Smile

To Do:

  • Show how to use IWML Runner
  • add click event
  • SetParam