1. Introduction

This document describes the form builder module. This module is used by software developers in specialized projects that need to generate edoras forms dynamically in Java. It provides Java builder APIs for individual form widgets and the form itself. These builders are used to generate an object representation of the form, which can then be converted directly to the corresponding JSON description. This JSON is then used by the edoras forms engine running in the browser.

1.1. Prerequisites

This document assumes a familiarity with edoras form concepts such as the form layout mechanism and the functionality supported by the available form widgets. This information can be found in the {modelerGuide}.

2. Obtaining the form builder

To include the form builder into your project you just need to add a dependency on the form builder JAR file, for example as a dependency in your Maven pom.xml:

Form builder dependency in Maven pom.xml
  <dependency>
          <groupId>com.edorasware.one</groupId>
          <artifactId>edoras-forms-builder</artifactId>
          <version>1.5.0.S81</version>
  </dependency>

3. Using the form builder

3.1. Overview

The following tutorial introduces the fundamental form builder concepts, and describes how a form description can be assembled and used to generate the corresponding JSON. Detailed documentation for the form builder API is provided in the form builder javadoc which can be obtained from edorasware support. Details of the functionality supported by specific form widget types and usage examples can be found in the edoras one Modeler Guide.

3.2. Widget builders

Before we can create a form we need to be able to create individual form widgets.

The form builder classes are located in the package com.edorasware.forms.builder, and builders for individual form widgets are located in the com.edorasware.forms.builder.component sub-package.

3.3. Creating a simple form widget

For very simple form widgets there are not many configuration options and these widgets can therefore be created directly with the standard Java new operator, providing the appropriate constructor parameters as required.

As an example, a spacer widget can be created as follows:

Creating a spacer widget
  EdorasFormComponent component = new SpacerComponent(3);
Tip

All form widget objects generated by the widget builders implement the EdorasFormComponent interface. This interface allows form widget references to be stored in type-safe collections or passed around without having to know the specific widget type.

The following form widgets are instantiated directly using constructors:

  • SpacerComponent

3.4. Creating a complex form widget

Other than the exceptions described above, most form widgets have a wide range of possible configuration options. For these complex widgets a fluent builder API is provided instead of a simple constructor. Any mandatory configuration parameters must be provided when the builder is created, and additional settings can then be made using the builder API before the final widget instance is produced.

As an example, a text widget can be created as follows:

Creating a text widget
  // Create the component builder
  TextComponent.Builder builder = TextComponent.builder("id123", "{{textValue}}");
  
  // Adjust the optional settings
  builder.required(true).size(3);
  
  // Instantiate the component from the builder
  TextComponent component = builder.build();

As the builder provides a fluent API, the configuration method calls can be chained together and combined into a single statement:

Creating a text widget in a single statement
  TextComponent component =
          TextComponent
                  .builder("id123", "{{textValue}}")
                  .required(true)
                  .size(3)
                  .build();

This pattern is followed by all widget builders, with the appropriate variations in the supported configuration parameters.

3.5. Creating an empty form

The first step when creating a form is to create the form builder itself. A form builders is instantiated using the static factory method EdorasForm.builder(). When the builder has been created, the required form widgets can be added as required and the assembled form is then created by calling the build() method on the form builder. The following example shows how to create an empty form:

Creating an empty form with the form builder
  EdorasForm.Builder builder = EdorasForm.builder();
  EdorasForm form = builder.build();

3.6. Adding form widgets

As described in the edoras one Modeler Guide, edoras one form widgets are laid out in rows where each row is made up of 12 slots and a widget can span multiple slots within the row. Vertical spans across rows are not supported.

The form builder creates rows as required, with the first widget being added to the first free slot in the current row (building from left to right). The following example shows the construction of a form with a single row containing three widgets:

Adding widgets to the form
  EdorasForm.Builder builder = EdorasForm.builder();
  builder.add(TextComponent.builder(
          "t1", "{{value1}}").label("Test 1", Alignment.TOP).size(2).build());
  builder.add(TextComponent.builder(
          "t2", "{{value2}}").label("Test 2", Alignment.TOP).size(3).build());
  builder.add(TextComponent.builder(
          "t3", "{{value3}}").label("Test 3", Alignment.TOP).size(4).build());
  EdorasForm form = builder.build();
example1

If there are not enough free slots to add the new widget in the current row then a new row will be created automatically. In the following example the final widget is too big to fit in the remaining 3 slots, so a new row is created:

Automatic creation of a new row
  EdorasForm.Builder builder = EdorasForm.builder();
  builder.add(TextComponent.builder(
          "t1", "{{value1}}").label("Test 1", Alignment.TOP).size(3).build());
  builder.add(TextComponent.builder(
          "t2", "{{value2}}").label("Test 2", Alignment.TOP).size(6).build());
  builder.add(TextComponent.builder(
          "t3", "{{value3}}").label("Test 3", Alignment.TOP).size(9).build());
  EdorasForm form = builder.build();
example2

It is also possible to explicitly force the creation of a new row, which will then receive any further widgets that are added:

Explicit creation of a new row
  EdorasForm.Builder builder = EdorasForm.builder();
  builder.add(TextComponent.builder(
          "t1", "{{value1}}").label("Test 1", Alignment.TOP).size(3).build());
  builder.nextRow();
  builder.add(TextComponent.builder(
          "t2", "{{value2}}").label("Test 2", Alignment.TOP).size(6).build());
  builder.add(TextComponent.builder(
          "t3", "{{value3}}").label("Test 3", Alignment.TOP).size(9).build());
  EdorasForm form = builder.build();
example3

To alter the horizontal placement of a widget within a row, a spacer widget of the appropriate size can simply be inserted beforehand (either at the start of a row or within it):

Using spacer widgets
          EdorasForm.Builder builder = EdorasForm.builder();
          builder.add(new SpacerComponent(3));
          builder.add(TextComponent.builder(
                  "t1", "{{value1}}").label("Test 1", Alignment.TOP).size(3).build());
          builder.nextRow();
          builder.add(TextComponent.builder(
                  "t2", "{{value2}}").label("Test 2", Alignment.TOP).size(3).build());
          builder.add(new SpacerComponent(3));
          builder.add(TextComponent.builder(
                  "t3", "{{value3}}").label("Test 3", Alignment.TOP).size(3).build());
          EdorasForm form = builder.build();
  
          String json = FormBuilderUtil.toJson(form);
          with(json).assertThat("$.rows", hasSize(2))
                  .assertThat("$.rows[0].cols", hasSize(2))
                  .assertThat("$.rows[1].cols", hasSize(3))
                  .assertEquals("$.rows[0].cols[1].label", "Test 1")
                  .assertEquals("$.rows[1].cols[0].label", "Test 2")
                  .assertEquals("$.rows[1].cols[2].label", "Test 3");
      }
  
      @Test
      public void addCollection() throws JsonProcessingException {
          List<EdorasFormComponent> components = new LinkedList<>();
          components.add(TextComponent.builder("t1", "{{value1}}").size(2).build());
          components.add(TextComponent.builder("t2", "{{value2}}").size(3).build());
          components.add(TextComponent.builder("t3", "{{value3}}").size(4).build());
  
          EdorasForm.Builder builder = EdorasForm.builder();
          builder.addAll(components);
          EdorasForm form = builder.build();
  
          String json = FormBuilderUtil.toJson(form);
          with(json).assertThat("$.rows", hasSize(1)).assertThat("$.rows[0].cols", hasSize(3));
      }
  
      @Test
      public void addVarargs() throws JsonProcessingException {
          TextComponent t1 = TextComponent.builder("t1", "{{value1}}").size(2).build();
          TextComponent t2 = TextComponent.builder("t2", "{{value2}}").size(3).build();
          TextComponent t3 = TextComponent.builder("t3", "{{value3}}").size(4).build();
  
          EdorasForm.Builder builder = EdorasForm.builder();
          builder.addAll(t1, t2, t3);
          EdorasForm form = builder.build();
  
          String json = FormBuilderUtil.toJson(form);
          with(json).assertThat("$.rows", hasSize(1)).assertThat("$.rows[0].cols", hasSize(3));
      }
  }
example4

As well as adding individual widgets to the form, it is also possible to add multiple widgets with a single call, either as a collection:

Adding multiple widgets as a collection
  List<EdorasFormComponent> components = new LinkedList<>();
  components.add(TextComponent.builder("t1", "{{value1}}").size(2).build());
  components.add(TextComponent.builder("t2", "{{value2}}").size(3).build());
  components.add(TextComponent.builder("t3", "{{value3}}").size(4).build());
  
  EdorasForm.Builder builder = EdorasForm.builder();
  builder.addAll(components);
  EdorasForm form = builder.build();

or using a varargs list:

Adding multiple widgets with varargs
  TextComponent t1 = TextComponent.builder("t1", "{{value1}}").size(2).build();
  TextComponent t2 = TextComponent.builder("t2", "{{value2}}").size(3).build();
  TextComponent t3 = TextComponent.builder("t3", "{{value3}}").size(4).build();
  
  EdorasForm.Builder builder = EdorasForm.builder();
  builder.addAll(t1, t2, t3);
  EdorasForm form = builder.build();

3.7. Creating the form JSON

When an EdorasForm definition has been created using the form builder, it can be converted into the corresponding JSON representation using the static FormBuilderUtil.toJson() method:

Creating the form JSON
  String json = FormBuilderUtil.toJson(form);