Quick Start

The following examples assume that there is a Message model on the server with title and description. We further assume that the model is accessible through a REST API where an HTTP GET request for a message’s URL, message/<id>, returns JSON data representing the current values, while an HTTP POST request for message/<id> accepts JSON data to update the model.

Note: Field values will be sent to the server one by one as they are edited. This means that if your model applies validation rules that consider multiple fields at the same time, you need to be careful to provide useful default values to make sure that any edits to form fields can be stored even if a model object has just been created.

Rendering a Form

First install ajja via bower (or fanstatic or manually)

bower install ajja

Add a placeholder inside your DOM

<div id="form"></div>

Initialize the form via ajja and load current state from server

var form = new ajja.Form("form");
form.load("message/1");

The response from the server should look like {"title": "", description: ""} and is analysed to create an input field for each attribute. The type of the input field is based on the data type of each attribute and defaults to a simple text input for empty / null values.

On load the placeholder will be replaced by the following HTML

<form method="POST" action id="form" class="ajja form-horizontal">
    <div class="statusarea"></div>
    <div class="field form-group" id="field-title">
        <label for="title" class="col-sm-3 control-label"></label>
        <div class="col-sm-9">
            <input type="text" data-bind="value: title" name="title" class="form-control" value />
        </div>
        <div class="col-sm-offset-3 col-sm-9">
            <div class="help-block error"></div>
        </div>
    </div>
    <div class="field form-group" id="field-desciption">
        <label for="desciption" class="col-sm-3 control-label"></label>
        <div class="col-sm-9">
            <input type="text" data-bind="value: desciption" name="desciption" class="form-control" value />
        </div>
        <div class="col-sm-offset-3 col-sm-9">
            <div class="help-block error"></div>
        </div>
    </div>
</form>

Each input field contains a Knockout binding via data-bind="value: {{name}}" to track changes. Those changes are pushed to the server by a POST request to message/id on focus-out. There is a defined communication protocol that the server end point at message/id needs to implement.

If server-side validations result in an error, a flash message will be rendered inside <div class="statusarea"></div>. If the response contained a msg it will be displayed inside <div class="help-block error"></div> beneath the input field that was just saved.

As you can see the generated HTML contains CSS classes compatible with Bootstrap, thus including the Bootstrap CSS is enough to make this form look pretty.

Customizing form fields

If you want to display a label next to each input field, declare title as required and to use a textarea for description, you can call form.load with an additional options dict like

var form = new ajja.Form("form")
form.load("message/1", {
    title: {"label": "Title", "required": true},
    description: {"label": "Body", "template": "form_text"}
});

Initializing form without AJAX request

Instead of loading data from an REST endpoint you can also provide the JSON data directly to the load function

var form = new ajja.Form("form")
form.load(
    {"title": "My brand new form", "description": ""},
    {
        title: {"label": "Title", "required": true},
        description: {"label": "Body", "template": "form_text"
    }
});

Note, that you will need to provide a save url in order to make the automatic pushes on field change work.

Rendering a Collection

It is assumed, that you already installed ajja.

Add a placeholder inside your DOM

<div id="my_collection"></div>

Initialize the collection (in this case a ListWidget()) and load current state from server

var collection = new ajja.ListWidget(
    '#my_collection',
    {collection_url: '/messages.json',
     default_form_actions: [],
     form_options: {
        'title': {label: 'Title'},
        'description': {label: 'Body'}
}});
collection.reload();

The response from the server is described in the protocol section.

On reload the placeholder will be replaced by the following HTML

<ul id="collection" class="list-group list-collection nav nav-stacked">
    <li id="item_" style="min-height: 50px;" class="list-group-item">
        <span class="actions btn-group badge">
            <a href="#" class="edit btn btn-default btn-xs" data-action="edit">
                <span class="glyphicon glyphicon-edit"></span> Edit</a>
            <a href="#" class="del btn btn-default btn-xs" data-action="del">
                <span class="glyphicon glyphicon-trash"></span> Delete</a>
        </span>
        <span class="content">
            <dl>
                <dt>title</dt>
                <dd>The title</dd>
                <dt>description</dt>
                <dd>The description</dd>
            </dl>
        </span>
    </li>
</ul>
<div id="form-actions">
    <a href="#" class="btn btn-default btn-sm add">
        <span class="glyphicon glyphicon-plus"></span> Add
    </a>
</div>

Each item has two default actions: edit and delete. The collection has the default action add. Add and edit both create a bootstrap modal dialog containing a ajja.Form form.

As you can see the generated HTML contains CSS classes compatible with Bootstrap, thus including the Bootstrap CSS is enough to make this form look pretty.

The form_options argument can be used the same way as options for a Form() to customize the look and behaviour of the form that is used for adding and editing collection items.

Collection types

ListWidget

The ListWidget() renders items as HTML lists. List items are rendered as HTML definition lists. Please refer to the section collection initialization for details about the default list widget.

GroupListWidget

The GroupListWidget() behaves similar to the ListWidget except that it groups items by a defined attribute.

var collection = new ajja.GroupListWidget(
    '#my_collection',
    {group_by_key: 'title',
     group_title_key: 'title',
     collection_url: '/messages.json',
     default_form_actions: [],
     form_options: {
        'title': {label: 'Title'},
        'description': {label: 'Body'}
}});
collection.reload();

Groups are created dynamically and items sorted into those groups by group_by_key. The title for the groups is taken from the attribute group_title_key.

TableWidget

The TableWidget() renders items in a HTML table.

var collection = new ajja.TableWidget(
    '#my_collection',
    {collection_url: '/messages.json',
     default_form_actions: [],
     form_options: {
        'title': {label: 'Title'},
        'description': {label: 'Body'}
}});
collection.reload();

Customizing the HTML output

It is possible to change the rendered HTML by overriding the default templates. Please refere to ajja.register_template() for information about how default templates are customized.

The following default templates are used by ListWidgets:

list
The main template for the list collection.
list_item_wrapper
Wrapper template for each item of the collection.
list_item
Template for the content of an item.
list_item_action
Template for an item action (edit, delete).
list_item_edit
Template for add or edit form (modal dialog) of an item.

GroupListWidgets use these templates in addition:

group
The main template for the group collection.
group_item
Template for a group item. Contains one ListWidgets.

TableWidgets just use these templates:

table
The main template for a table collection.
table_head
Template for head part of the table.
table_row
Template for a row of a table. Contains data and actions.
list_item_edit
The same template as for ListWidgets.