Wednesday, April 23, 2014

Anatomy of a Control Template

In this post I will explain some rules I use to create a template for a control.
Let's look at the template for a TextBox control.

<div id="{{id}}_template" class="redui-textbox-outer redui-valid{{#model.cssClass}} {{model.cssClass}}{{/model.cssClass}}{{#model.isHidden}} redui-hidden{{/model.isHidden}}">
  {{#model.label}}<label for="{{id}}" class="redui-textbox-label">
    <span>{{#_localize}}{{model.label}}{{/_localize}}: {{#model.isRequired}}*{{/model.isRequired}}</span>
  </label>{{/model.label}}
  <input id="{{id}}" name="{{name}}" data-name="{{name}}" class="redui-textbox redui-focusable" type="{{model.inputType}}" />
  <div id="{{id}}_validationerrorbox" class="redui-validation-errorbox"></div>
{{#contextMenu}}{{{_toHtml}}}{{/contextMenu}}</div>


What we see here?

1. Main tag

Every control has an HTML tag that it is build around. For the TextBox it is, natuarally, the input tag.

<input id="{{id}}" name="{{name}}" data-name="{{name}}" class="redui-textbox redui-focusable" type="{{model.inputType}}" />

This is the most important part of the template.

id - stores the unique id of the control, something like 'redui_control_123'. Unique id are assigned to every control upon its creation.

name - the name of the control, that you provide in the model.

for example, if you defined you TextBox as follows:

{
 "name": "firstNameTextBox",
 "type": "textbox",
 "label": "First Name",
 "bindsTo": "firstName"
}


the name attribute will be filled with 'firstNameTextBox'.

data-name - the same as name attribute. Not every HTML tag allows name attribute, but data-name attribute is always available.

class - here we put the class that reflects the control type. It has prefix 'redui-' followed by the type that you use in the model. For instance, for TextBox it is 'redui-textbox'.

2. Label

Most of the controls have label

{{#model.label}}<label for="{{id}}" class="redui-textbox-label">
  <span>{{#_localize}}{{model.label}}{{/_localize}}: {{#model.isRequired}}*{{/model.isRequired}}</span>
</label>{{/model.label}}

Label is optional, so when it is not set, this part of the template is not rendered. This part of the template is almost identical for every control, only class is different.

3. Outer div

One HTML tag is not enough even for the simplest control. In case of TextBox, it requires at least 2: input and label. To make it easier to target various tags with CSS-selectors they all are wrapped in one outer div.

<div id="{{id}}_template" class="redui-textbox-outer redui-valid{{#model.cssClass}} {{model.cssClass}}{{/model.cssClass}}{{#model.isHidden}} redui-hidden{{/model.isHidden}}">

By convention, this div has an id that matches the control id with suffix '_template'.
Second, it has class that matches the control class with suffix '-outer', in our case, 'redui-textbox-outer'.

The most important, when you apply the custom CSS class in the model, it is set on this outer element.

So for example, if apply class 'myControl',

{
 "name": "firstNameTextBox",
 "type": "textbox",
 "label": "First Name",
 "bindsTo": "firstName",
 "cssClass": "myControl"
}

It will be set on the outer div.

Naturally, visibility ('redui-hidden' class) is also applied to the outer div.

4. Validation div


By convention, this div has an id that matches the control id with suffix '_validationerrorbox'.
For controls that support validation this div is used to show the validation message.

5. Context menu


Every control can have a context menu attached to it. To show it you need to add this section:

{{#contextMenu}}{{{_toHtml}}}{{/contextMenu}}

6. Inner controls


For the container controls you need to render inner controls. The following section takes care of it:

{{#controls}}
{{{_toHtml}}}
{{/controls}}


Finally, some important classes used in templates:


redui-hidden
Hides the control

redui-focusable
When the window is open, the focus goes to the first control that has redui-focusable class

redui-valid
Controls whether validation div should be visible

redui-activated
For some controls the special behavior is enabled upon activation. For example, GridViewColumn subscribes to click event to allow sorting. To avoid the double activation, the class redui-activated is set on such a control after the behavior is activated

redui-disabled
This class is used together with commands. When the command is not available (canExecute returns false), controls that are bound to this command get the class redui-disabled

No comments:

Post a Comment