JSON Forms – Day 5 – Layouts

JSON Forms – Day 5 – Layouts

JSON Forms is a framework for efficiently building form-based web UIs. These UIs, which are usually embedded in a business application, allow end users to enter, modify, and view data. JSON Forms eliminates the need to write HTML templates and Javascript for data binding by hand. It allows you to create customizable forms by leveraging the capabilities of JSON and JSON schema and providing a simple and declarative way of describing forms. Forms are then rendered with a UI framework, currently one that is based on AngularJS. If you would like to know more about JSON Forms, the JSON Forms homepage is a good starting point.

In this blog series, we would like to introduce the framework based on a real-world example application, a task tracker called “Make It happen”. On day 1 and day 2, we described the overall requirements as well as created a fully working form for the entity “Task”. On day 3 we showed how to extend the form with new attributes and controls. On day 4 we introduced rule-based visibility of controls, based on the data, the user has entered.

If you would like to follow this blog series please follow us on twitter. This is where we will announce every new blog post regarding JSON Forms. After the first 4 days, the current form looks like this:

While the form is already fully functional, including data binding, validation, and even rule-based validation, the layout is definitely not optimal. Basically, we just see a vertical list of all controls. Therefore, in this blog post, we want to refine the layout using the JSON Forms layout elements.

So far, we have embedded all controls into one root “VerticalLayout”. This type of layout always arranges its children vertically. However, JSON Forms also supports different layout types, e.g. “HorizontalLayout”. Of course, those layouts can be combined by embedding one layout element into another. For example to achieve a two column layout you can use a “HorizontalLayout” element which contains two “VerticalLayout” elements.

In our current form, we could save some vertical space by putting the “dueDate” attribute in one shared “HorizontalLayout” with the “rating” property. The same applies for “recurrence” and “recurrence_interval”.

The resulting UI schema looks like this:

 <pre lang="JSON">
{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Control",
      "label": false,
      "scope": {
        "$ref": "#/properties/done"
      }
    },
    {
      "type": "Control",
      "scope": {
        "$ref": "#/properties/name"
      }
    },
    {
      "type": "HorizontalLayout",
      "elements": [
        {
          "type": "Control",
          "scope": {
            "$ref": "#/properties/due_date"
          }
        },
        {
          "type": "Control",
          "scope": {
            "$ref": "#/properties/rating"
          }
        }
      ]
    },
    {
      "type": "Control",
      "scope": {
        "$ref": "#/properties/description"
      },
      "options": {
          "multi":true
      }
    },
    {
      "type": "HorizontalLayout",
      "elements": [
        {
          "type": "Control",
          "scope": {
            "$ref": "#/properties/recurrence"
          }
        },
        {
          "type": "Control",
          "scope": {
            "$ref": "#/properties/recurrence_interval"
          },
          "rule": {
              "effect": "HIDE",
              "condition": {
                  "scope": {
                      "$ref": "#/properties/recurrence"
                  },
                  "expectedValue": "Never"
              }
          }
        }
      ]
    }
  ]
}
</pre> 

So by simply moving things around a bit in the UI schema, we can produce the following layout:

As you can imagine, it is pretty easy to produce more advanced layouts by just combining layout elements.

Please note, that EMF Forms supports more layout types than horizontal and vertical. As an example, you could use the element “Categorization” to separate controls into several sub categories. The following screenshot shows a rendered categorization element, where the attributes of a task are split into two tabs. Please note that the horizontal layout described before is now nested into the categorization.

The UI Schema for this layout is as follows:

 <pre lang="JSON">
{
  "type": "Categorization",
  "elements": [
    {
      "type": "Category",
      "label": "Main",
      "elements": [
        {
          "type": "Control",
          "label": false,
          "scope": {
            "$ref": "#/properties/done"
          }
        },
        {
          "type": "Control",
          "scope": {
            "$ref": "#/properties/name"
          }
        },
        {
          "type": "Control",
          "scope": {
            "$ref": "#/properties/description"
          },
          "options": {
              "multi":true
          }
        }
      ]
    },
    {
      "type": "Category",
      "label": "Additional",
      "elements": [
        {
          "type": "HorizontalLayout",
          "elements": [
            {
              "type": "Control",
              "scope": {
                "$ref": "#/properties/due_date"
              }
            },
            {
              "type": "Control",
              "scope": {
                "$ref": "#/properties/rating"
              }
            }
          ]
        },
        {
          "type": "HorizontalLayout",
          "elements": [
            {
              "type": "Control",
              "scope": {
                "$ref": "#/properties/recurrence"
              }
            },
            {
              "type": "Control",
              "scope": {
                "$ref": "#/properties/recurrence_interval"
              },
              "rule": {
                  "effect": "HIDE",
                  "condition": {
                      "scope": {
                          "$ref": "#/properties/recurrence"
                      },
                      "expectedValue": "Never"
                  }
              }
            }
          ]
        }
      ]
    }
  ]
}
</pre> 

Please refer to this page for an overview of the available layout elements in JSON Forms.

As you might have noticed, the layout types of JSON Forms are a little different from what you know from HTML or any widget toolkit. As an example, there is no element called “tabbed layout”, but rather, it is called “Categorization”. The reason for this is that the UI Schema of JSON Forms is focussed on describing the structure of the layout rather than the actual rendering. The concrete visualization is the responsibility of the rendering component. This is analogous to the combination of HTML and CSS and allows for flexibility in rendering. As an example, the categorization element described above basically only specifies, that a form is split into several categories. The default renderer will translate this information into tabs. However, you could also implement an alternative renderer, which would display categories slightly differently, e.g. like this:

Talking about alternative renderers: This is a core feature of JSON Forms! So far, we have just used the default renderer for controls as well as for layouts. In the next post, we will describe how to implement and plugin custom renderers in order to adapt the way in which a form is rendered. So stay tuned!

If you are interested in trying out JSON Forms, please refer to the Getting-Started tutorial. This explains how to set up JSON Forms in your own project and how you can try out the first few steps yourself. If you would like to follow this blog series, please follow us on twitter. We will announce every new blog post on JSON Forms there. If you need support for JSON Forms or if you are interested in new features, please feel free to contact us.

We hope to see you soon for the next day!

 

List of all available days to date:

No Comments

Post a Comment

Comment
Name
Email
Website