Create a Simple Widget

This example will show how you can create a widget (more generically, an element) using the Backbase Tag Definition Language (TDL). The example will not go deep into the matter. For more details on widget creation, refer to the Widget Development Guide and the Reference.chm.

Overview

When developing a widget, the first steps would be to design the widget. The design determines how the widget should look, what its functionality is and what the API should be. In this example, a very simple spinner will be created. The spinner will be a widget that has a numeric value, which can be incremented or decreased using buttons.

Creating a Simple Widget

The first step in developing this widget is to create the element definition in TDL.

Defining an element

Before an element can be used in the Backbase Client Framework, the element needs to be defined in TDL. The Backbase Tag Library (BTL) and XHTML have both been defined in TDL. The first thing needed to do anything in TDL is the tdl tag. This indicates the start of a TDL document (or part of a document). As all elements have to be part of a namespace, the second step is to define a namespace by adding the namespace tag as content of the tdl tag. For this example, the namespace will be http://www.mycompany.com. Finally, the element itself is defined by using the element tag. As we are creating a simple spinner, we'll call it mySimpleSpinner.

<d:tdl>
        <d:namespace name="http://www.mycompany.com">
                <d:element name="mySimpleSpinner">
                        ...
                </d:element>
        </d:namespace>
</d:tdl>

Snippet 1: Element definition

The result of the code in the first snippet is that we will be able to instantiate the mySimpleSpinner element of the http://www.mycompany.com namespace.

Defining the template

As it might be useful to have a visual representation of a widget when it is being developed we will define the template first. There are a few different types of templates. In this example we will use application/xhtml+xml. This is suitable for a static template. For a more dynamic template text/javascript can be used. If you want the view of an element to be the result of an XSL transformation, text/xsl can be used.

The simple spinner will consist of two buttons and an element that will be used for representing the current value of the spinner (the nested span). Because a template should always have one root node, the elements are wrapped by a span.

...
<d:element name="mySimpleSpinner">
        ...
        <d:template type="application/xhtml+xml">
                <span>
                        <span />
                        <button>-</button>
                        <button>+</button>
                </span>
        </d:template>
        ...
</d:element>
...

Snippet 2: Template definition

Now we can instantiate the simple spinner and see a result in the browser. Currently, only the two buttons will be visible as the span meant for displaying the value does not contain any value yet.

<d:tdl>
        <d:namespace name="http://www.mycompany.com">
                <d:element name="mySimpleSpinner_no_style">
                        <d:template type="application/xhtml+xml">
                                <span>
                                        <span />
                                        <button>-</button>
                                        <button>+</button>
                                </span>
                        </d:template>
                </d:element>
        </d:namespace>
</d:tdl>

<myprefix:mySimpleSpinner_no_style></myprefix:mySimpleSpinner_no_style>

Snippet 3: Simple spinner

The result is shown in the following live demo:

Live Demo 1: The simple spinner

Defining resources

The spinner in the first example is completely unstyled. In the end, our example will not look perfect, because we are trying to keep things simple, but it would be nice if we would add some styling to it. We will give the buttons a different color and add some space between the buttons and the span that will be used for displaying the value of the spinner.

The styling will be done using CSS. We add the CSS as a resource for the spinner. Different types of resources can be created (JavaScript, XML, images) and resources can also be located in separate files.

...
<d:element name="mySimpleSpinner">
        ...
        <d:resource type="text/css">
                .ns-mySimpleSpinner button {
                        background-color: #772222;
                        color: #FFF;
                        border-style: none;
                        margin-left: 3px;
                }
        </d:resource>
        ...
</d:element>
...

Snippet 4: CSS resource for mySimpleSpinner

<d:tdl>
        <d:namespace name="http://www.mycompany.com">
                <d:element name="mySimpleSpinner">
                        <d:resource type="text/css">
                                .ns-mySimpleSpinner button {
                                        background-color: #772222;
                                        color: #FFF;
                                        border-style: none;
                                        margin-left: 3px;
                                }
                        </d:resource>

                        <d:template type="application/xhtml+xml">
                                <span class="ns-mySimpleSpinner">
                                        <span />
                                        <button>-</button>
                                        <button>+</button>
                                </span>
                        </d:template>
                </d:element>
        </d:namespace>
</d:tdl>
<myprefix:mySimpleSpinner />

Snippet 5: TDL definition for mySimpleSpinner

Defining properties

Since we are creating a spinner, we need to know the value of the spinner. The value is a property of the spinner, so we define a property using TDL. A property has a name (in our case value), a setter and a getter. The setter is executed whenever the value of the property is set, and the getter is executed whenever the value of the property is retrieved. Properties have a default implementation for the setter and the getter, so they do not need to be defined, but they can be defined when there is need for a custom implementation. This can be a calculation or, in this case, a change in the view. Whenever the value of the spinner is set, we need to update the view to represent this value.

By default, the setter stores the property. The custom implementation of the setter overwrites this default behavior so the custom setter should also store the property. The getter returns the value that has been stored on this._['_name of property']. For the spinner this means that the setter should store the value on this._['_value'] or, with a different syntax, this._._value.

...
<d:element name="mySimpleSpinner">
        ...
        <d:property name="value">
                <d:setter type="text/javascript">
                        this.viewNode.getElementsByTagName('span')[0].innerHTML = value;
                        this._._value = String(value);
                </d:setter>
        </d:property>
        ...
</d:element>
...

Snippet 6: Property definition for mySimpleSpinner

Defining attributes

After creating the value property, the value attribute will be defined. The attribute will be used to set the initial value of the spinner element. The attribute can be used on the <myprefix:mySimpleSpinner> tag.

Attribute definitions can contain a mapper and a changer. The contents of the mapper will be executed when the element is instantiated and when the value of the attribute is changed. The changer is only executed when the value of the attribute is changed.

...
<d:element name="mySimpleSpinner">
        ...
        <d:attribute name="value" default="0">
                <d:mapper type="text/javascript">
                        this.setProperty('value', value);
                </d:mapper>
        </d:attribute>
        ...
</d:element>
...

Snippet 7: Attribute definition for mySimpleSpinner

Defining methods

...
<d:element name="mySimpleSpinner">
        ...
        <d:method name="decrement">
                <d:body type="text/javascript">
                        var sValue = this.getProperty('value');
                        var iValue = parseInt(sValue);
                        iValue--;
                        this.setProperty('value', String(iValue));
                </d:body>
        </d:method>

        <d:method name="increment">
                <d:body type="text/javascript">
                        var sValue = this.getProperty('value');
                        var iValue = parseInt(sValue);
                        iValue++;
                        this.setProperty('value', String(iValue));
                </d:body>
        </d:method>
        ...
</d:element>
...

Snippet 8: Method definitions for mySimpleSpinner

Defining event handlers

...
<d:element name="mySimpleSpinner">
        ...
        <d:handler event="click" type="text/javascript">
                var aButtons = this.viewNode.getElementsByTagName('button');
                if(event.viewTarget == aButtons[0]){
                        this.decrement();
                } else if(event.viewTarget == aButtons[1]){
                        this.increment();
                }
        </d:handler>
        ...
</d:element>
...

Snippet 9: Event handler definition for mySimpleSpinner

Using the element

<d:tdl>
        <d:namespace name="http://www.mycompany.com">
                <d:element name="mySimpleSpinner">
                        <d:resource type="text/css">
                                .ns-mySimpleSpinner button {
                                        background-color: #772222;
                                        color: #FFF;
                                        border-style: none;
                                        margin-left: 3px;
                                }
                        </d:resource>

                        <d:template type="application/xhtml+xml">
                                <span class="ns-mySimpleSpinner">
                                        <span></span>
                                        <button>-</button>
                                        <button>+</button>
                                </span>
                        </d:template>

                        <d:property name="value">
                                <d:setter type="text/javascript">
                                        this.viewNode.getElementsByTagName('span')[0].innerHTML = value;
                                        this._._value = String(value);
                                </d:setter>
                        </d:property>

                        <d:attribute name="value" default="0">
                                <d:mapper type="text/javascript">
                                        this.setProperty('value', value);
                                </d:mapper>
                        </d:attribute>

                        <d:method name="decrement">
                                <d:body type="text/javascript">
                                        var sValue = this.getProperty('value');
                                        var iValue = parseInt(sValue);
                                        iValue--;
                                        this.setProperty('value', String(iValue));
                                </d:body>
                        </d:method>

                        <d:method name="increment">
                                <d:body type="text/javascript">
                                        var sValue = this.getProperty('value');
                                        var iValue = parseInt(sValue);
                                        iValue++;
                                        this.setProperty('value', String(iValue));
                                </d:body>
                        </d:method>

                        <d:handler event="click" type="text/javascript">
                                var aButtons = this.viewNode.getElementsByTagName('button');
                                if(event.viewTarget == aButtons[0]){
                                        this.decrement();
                                } else if(event.viewTarget == aButtons[1]){
                                        this.increment();
                                }
                        </d:handler>
                </d:element>
        </d:namespace>
</d:tdl>

<myprefix:mySimpleSpinner value="50"></myprefix:mySimpleSpinner>

Snippet 10: Styled spinner

The result is shown in the following live demo:

Live Demo 2: Styled spinner

Conclusion

In summary, this example has shown you how to define and develop new widgets of your own design. The completed widget can be used on your own web page like any other widget.

Download

You can download a zipped version of the examples provided on this page to try them out for yourself.

Note: Make sure to extract the content of this zip file to the root folder of your web server or application server (for example, htdocs), and then run it from your local development environment.

Additional Resources

For more information on TDL, refer to the following documentation: