Kauri Documentation
 PreviousHomeNext 
Further reading:Book Index10.2 Standard Usage

10.1 Concepts

Goals and Features

Made for data-entry: managing a data-structure

As explained in the introduction the Kauri Forms framework is about creating interaction screens to allow management of structured data. A typical example of such structured data in JSON notation would look like this:

{
  "name": "John Doe",
  "sex": "Male",
  "birth": "19700605",
  "hobbies": ["family", "reading" , "math", "stars", "trains", "photography"],
  "address": {
    "street": "Longstreet",
    "number": "5758",
    "zip": "TX 3007",
    "city": "Hometown",
    "country": "Belgium"
  }
}

As the example shows these data-structures are by nature composed of different members that in their own right can be either

Assuming the REST services to manage these entities (store, retrieve, query, secure, ...) are available the forms-framework is there to help create browser based interaction screens and logic

  1. to modify these structures,
  2. validate the data-entry and finally
  3. communicate with the available back-end services
Made for real life applications

The difference between good and great applications appeals for the kind of end-user interaction that goes beyond assuring the dull correctness of data entry, and aspires to make a difference that matters in how the end-user can efficiently perform his daily work.

In our experience the nowadays web-based front-end designers up for the challenge have a great deal of low level HTML, CSS and Javascript experience. In order to support them, the framework should allow them to leverage that experience and focus on making 'the difference'. In other words: the dull stuff should be handled correctly out of the box and extras and customisations should be easily possible.

In practice we allow

  1. Extending the framework with custom controls and features.
  2. Extensively configuring the available components.
  3. Standard HTML/CSS editing of the visual UI components.
  4. Wiring up events between the various form controls internally, or between the form-controls and custom Javascript functions and non-Kauri UI libraries.

How all that is done we explain in this section, after some general introduction.

Essential Framework Concepts and terminology

The framework introduces 3 distinct concepts with their own specific goals and responsibilities:

  1. Fields
  2. Controls
  3. The Form
A Field

A 'Field' in Kauri Forms groups the 'data-type' aspects of each individual low-level member in the data-structure. These aspects are:

  1. value properties, e.g.
  2. formatting properties
  3. validation properties
  4. extra convenience properties

For handling some recurring data-types, the framework already offers a number of standard 'Field' implementations:

Next to these, own fields can be added.

The core task of these Fields is to keep track of the 'value' being offered for editing in the form. This involves triggering and managing validation, but also converting the value to-from the (string) representations of it that are either entered/seen by the end-user or communicated to the back-end.

Note that both towards the backend (json/wire-format) and to the end-user (keyboard-entry and screen-feedback) all communication is essentially string based (or 'untyped' if you like).

For this purpose the Field knows about two distinct 'formatter's that handle formatting (to string) and parsing (from string) of the actual value. These two are known respectively as the:

  1. wire-formatter: to convert the local value to-from the value as passed over the wire (ie. JSON)
  2. user-formatter: to convert the local value to-from the value as shown and edited by the end-user.

Note that any occuring formatting and parsing errors will be presented to the end user in the same way as validation errors: both indicate invalid data in the form and require a similar action to get resolved.

Just like the formatting logic, the actual validation logic is provided in separate (reusable) classes that implement a simple validation interface. Its responsibility is to evaluate a single value leading to either an ok or to a validation-message.

A Control

A 'Control' then will, for each distinct member in the data-structure, offer the graphical screen elements to show its value and allow changing it. In more detail this involves:

  1. Produce a specific UI Control (set of activated HTML elements) to allow the required end-user interaction. This includes input-elements, specific action triggers, labels, format or validation feedback, ...
  2. Rely on a specific 'Field' to properly handle the data-type related aspects of the values being modified through the control.
  3. Bind to user-input events to trigger formatting, validation and fire events.
  4. As well as bind to events from other controls
  5. And depending on the specific control: load reference data from specific configured URI's

More or less matching the earlier mentioned typical Fields (datatypes) the Kauri-forms module offers these 'Control' implementations:

Just like with the Fields, your own custom controls can be added.

The Form

Finally the Form object in this framework is the corner-piece in the whole setting that organizes the various controls on the screen and handles the communication to the rest-services. For that it will:

  1. Act as a top-level composite Control holding the first-level members.
  2. Read the HTML template for matching elements and extract a basic "configuration" from it.
  3. Apply an optional external form-configuration.
  4. Create and set-up all nested controls. (including the top-level control provided by itself)
  5. And maintain a registry of controls to allow lookup and referencing between them.
    (Useful in e.g. event-binding and handling)
  6. Last but not least, it will communicate to the back-end upon form-submit.

Form Configuration (aka fconf)

To make the Form manage the data-structure of your choice (i.e. show the correct fields, and apply the desired formatting and validation) you need to give it the proper "configuration".

This configuration holds a number of things:

  1. a description of the various members of the data-structure and how the form should allow modifying them.
  2. the service URIs needed for data-submission
  3. specific form properties

Matching the sample data-structure from the first paragraph, below you find a rough structure of an appropriate matching form configuration:

var fconf = {
  /* described data structure */
  "members": {
    "name":    {   /* some string input */          },
    "sex" :    {   /* Male or Female choice */      },
    "birth:    {   /* date input */                 },
    "hobbies": {   /* flexible list of strings */   },
    "address": {   /* nested structure of street, number, zip, city and country */...}
  }  

  /* communication properties */
  "createURI": "${publicUri('service:/data/person/')}",

  /* Additional custom types */
  "controlTypes": {
     "name-of-control": {  /*   definition */   }
  }
}

Roughly speaking there are 3 main sections in this configuration:

  1. The listing of form-members and their (inline) field-type descriptions.
  2. Form-specific properties, mainly to configure the communication end-points for form-submit.
  3. Possible additional custom types (for fields, controls, formatters and validators) to reference to.

See the reference 'form config' for a more detailed explanation of what should go in each section. Additionally check the reference on each of the controls you want to use to learn about how they can be configured and tuned. Below you just find some simple examles as a first introduction into the nested field-description:

...
  "members":   {
     "name": "string",   //a shorthand for { "base": "string" }

     "birth": {
       "base": "date",
       "yearRange": '-100:+0',

       "label": 'What is your date of birth?'
     },

     "address": {
       "base" : "composite", 
       "members": {
         "street"   : "string",
         "nr"       : "string",
         "zip"      : "string",
         "city"     : "string",
         "country"  : "string"
       }
     }
   }
...

Note how the composition/nesting of members in this structure enables to give each control in the hierarchy a unique absolute-id by concatenating them into 'paths'. We call the resulting full-identification the control "index". So in the above example the following ones will have been created.

  /name
  /birth
   ...
  /address
  /address/street
  /address/zip
   ...

These "indices" will turn up again when we talk about the HTML Template binding further down.

Finally, to complete the 'form' explanation we just need to explain how to turn this form-configuration into a live form. This involves:

  1. the following lines of Javascript:
      var form=new $.org.kauriproject.forms.Form("my-form", fconf);
  2. and an HTML <form> element that matches up with the id (mentioned as first argument):
      <form id="my-form" />

HTML Form Creation

As shown above the matching <form/> element can be kept empty. In that case the Javascript framework will create all the required HTML elements to enable the needed end-user interaction. (as hinted above this is under the responsibility of the different controls)

TODO: describe current match/create algorithm that decides when to start creating elements --> some of this still under discussion (see mail-list, see issue?)
+ position and importance of "input" element

HTML Template Binding

Of course those elements will be created and positioned in some standard way as coded inside the specific controls (each of them might allow some configuration to tweak that a bit). Instead of sticking to that default the framework allows to "bind" the interaction behaviour of the distinct controls to specific (and arbitrary positioned) HTML elements in a custom provided page.

To make the binding work however these HTML elements need some additional mark-up that declares them as:

  1. Being tied to a specific control. By using the @kauri-idref attribute.
  2. Being created to fulfill a specific function or role. Through the @kauri-role attribute.

As an example:

<label kauri-idref="name" kauri-role="label">Name:</label>
<input kauri-idref="name" kauri-role="input" />
<span  kauri-idref="name" kauri-role="messages" />

This allows the front-end designer to arbitrarily position the label, input-box and feedback messages (typically format and validation errors) associated to the control.

For ease-of-typing the kauri-idref attribute is inherited down the nodes in the HTML structure. This means that the value can be placed on a common parent for various nested elements:

<div kauri-idref="name"> 
  <label kauri-role="label">Name:</label>
  <input kauri-role="input" />
  <span  kauri-role="messages" />
</div>

Remember that controls can be nested (This is how composite controls manage composite values.) In this case the member-names are combined into an absolute id or "index" for the control.

The @kauri-idref value should point to this index, but can choose to do so in a relative way. By default the kauri-idref value will be appended to the one of any parent element in the HTML structure. Only if the value kauri-idref starts with a '/', the value is considered to be absolute.

Note:
Relative-path-traversing syntax (i.e.: './' or '../' prefixes) are NOT supported in the @kauri-idref
Further explanation on the kauri-idref, plus a complete list of the supported 'kauri-roles' is to be found in the 'form HTML' reference.

Blending HTML Template and Configuration

The more people make use of the customization possibilities of the HTML template, or more technically: the more nested kauri-idref attributes are found on the HTML elements nested in the <form> tag, the more of the data-structuring information the system can derive from it.

This derived structure is effectively taken into account and thus avoids the double typing of providing the complete structure in the form-config as shown above.

While these kauri-idref values are a simple and flexible alternative for expressing some implicit structure, they are no match for the expressiveness of the JSON form-config for more elaborate stuff like specific control settings. To match up the best of both worlds we allow the @kauri-type attribute to associate pre-configured control-types to the identified (by kauri-idref) controls.

These pre-configured control-types are listed (using their name as a property-key) in the fconf['controlTypes'] object.

For more details, check the 'form HTML' and 'form config' reference for more details on this usage.

Event Handling and wiring

For the event-handling kauri-forms just relies on the jQuery event mechanism.

All regular jQuery event handling applies, and any additional kauri-specific events are bound and triggered through the matching "input" element.

Getting a handle to this element is easy:

  1. First lookup the control you want to bind to with CONTROL#findControl(path). This path argument can be absolute (starting with '/') or relative (NOTE: traversing the hierarchy with '../' is supported here)
  2. on the found control the method CONTROL#getElement() will return the jQuery wrapped HTML element handling the 'input' role which is passing on all the events.

In a code-sample:

  var form = new $.org.kauriproject.forms.Form("my-form", fconf);
  var wzip = form.findControl('/address/zip');
  wzip.getElement().valueChanged(function() {
    alert("The zip value changed to: ", wzip.getValue());
  });

Further reading:

 PreviousHomeNext 
Further reading:10.2 Standard Usage