ZK Form Builder: Automating Form Generation

From Documentation
DocumentationSmall Talks2025FebruaryZK Form Builder: Automating Form Generation
ZK Form Builder: Automating Form Generation

Author
Hawk Chen, Manager, Potix Corporation
Date
February 25, 2025
Version
formbuilder 0.9.0


Overview

Enterprise applications often require large, complex forms with hundreds of input fields, such as Name, Age, Gender, Address, and more. Traditionally, developers must manually define each field in ZK, bind them to data models, and handle validation — resulting in excessive code, redundancy, and maintenance challenges.

To simplify this process, we are developing a prototype of the ZK Form Builder. This tool allows developers to define form structures and templates, which can then be used to automatically generate ZK forms with the necessary components and bindings. This prototype showcases our vision — please try it out and share your feedback for improvements!


Form builder1.gif

What’s a Form?

A form is a structured collection of input fields that allows users to enter and submit data. It is typically organized in a grid layout to enhance readability and alignment.

FormModel Represents a Form

To streamline the form creation process, we introduce the FormModel, which serves as a tree-structured container for field information (FormField). This model is then used to dynamically generate ZUL content or ZK components, minimizing manual effort in form building.

Formbuild-architecture.png

A FormModel consists of multiple FormFields, each representing an individual input field within the form. But before we dive into assembling a full form, let's first define the structure of a single FormField.

Defining a Basic Form Field Structure

Each field in a form consists of:

  • A label
  • An input component
  • A default value (optional)

A form can have more features like validation, but let’s keep it simple for now.

Using this concept, we create FormField as follow:

public class FormField {

	private String name; //input label
	private String type; //input type, determine to render with which field template
	private Object value; //the value of the input component, could be String or Number
...
}

Now that we have the foundation of a FormField, the next step is to see how multiple fields come together to form a complete form.

Creating a Form by Adding FormFields

Building a form is simply a matter of adding various types of FormFields into a FormModel.

formModel = new FormModel();
formModel.add(new FormField("Project Name", "shortText", "Summer Product Launch"));
formModel.add(new FormField("Deadline", "date", null));

However, a form is not just a collection of fields —it also needs a layout and structure to determine how these fields are displayed. This is where form templates come into play.

Template ZUL

The Form Builder generates a form in zul by combing a form template and a FormModel.

Formtemplate.png

Form Template

A Form Template defines the overall layout of a form. Instead of manually specifying the structure for each form, we provide built-in templates written in ZUL with the Velocity template language. These templates allow for consistent formatting and easy customization

Here's an example of a form template:

 1     <grid apply="org.zkoss.formbuilder.FormComposer" width="30%">
 2         <columns>
 3             <column label="name"/>
 4             <column/>
 5         </columns>
 6         <rows>
 7         #foreach( $rowContent in $rowsContent )
 8             <row>$rowContent</row>
 9         #end
10             <row>
11                 <cell colspan="2" align="right"><button label="save" id="savebtn"/></cell>
12             </row>
13         </rows>
14     </grid>
  • Line 1: it applies a default controller
  • Line 7-9: each row contains a field that is generated by a field template.

While a form template defines the structure of the entire form, each individual FormField also needs a corresponding Field Template to determine how it is rendered.

Field Template

Each field is generated based on a FormField and a corresponding template. A field template is also a zul file with Velocity template language under the formbuilder.jar/template/.

Fieldtemplate.png

For example, a field template for a short text input looks like this:

shortText.zul

<label value="$name" /><textbox value="$value" id="$name" />
  • $name: FormField.name
  • $value: FormField.value

The file name of the template matches the FormField.type. For instance, if a FormField has a type of shortText, the Form Builder will generate the field using the corresponding template.

Now that we've covered both form-level and field-level templates, let's see how everything comes together to generate a complete form.

Build a Form

Building a form with the Form Builder primarily involves:

  1. Constructing a FormModel with various FormFields
  2. Choosing an output format: either in ZUL format (for UI generation) or Java objects (for backend processing)

By combining these steps, developers can automatically generate forms with minimal manual effort, improving both development speed and maintainability.

Now, let’s explore different ways to build forms depending on the source of the form structure.

Use Case 1: Building Form Fields in Java Directly

If you already have a defined form structure in mind, you can directly create the form by instantiating a FormModel object in Java. This approach is best suited for forms with predefined, static fields that do not change dynamically.

FormModel formModel = new FormModel();
formModel.add(new FormField("Project Name", "shortText", "Summer Product Launch"));
formModel.add(new FormField("Deadline", "date", null));

Then generate the zul content for further processing:

String zulContent = formModel.toZul();

While this method provides direct control over form structure, it may not be ideal when dealing with dynamic or external data sources. In such cases, converting source data into a form dynamically is a better approach.

Use Case 2: Converting Source Data into ZUL

Many enterprise applications derive their form structures from external data sources such as JSON, XML, or properties files. In this approach, you parse the external data and convert each entry into a FormField, dynamically building the form.

For example, if a JSON object defines the form structure, the system needs to parse the JSON properties and generate corresponding FormFields based on their attributes.

	private FormNode getNodeFromJsonObject(JSONObject jsonObjectNode) {
                ...
		ArrayList<FormNode> children = new ArrayList<FormNode>();
		//parse json object to determine name, type, value
		FormNode newNode = new FormNode(new FormField(name, type, value), children);
		return newNode;
	}

If your form requires a nested structure (such as sections with grouped fields), you can use a FormNode, which acts as a container holding child FormNode within the FormModel tree.

Once the model is structured, the next step is to generate the ZUL content and render it as UI components on the page.

String zulContent = formModel.toZul();
Executions.createComponentsDirectly(zulContent, null, host, null);

This method is useful when you need to generate ZUL dynamically based on changing data, but sometimes you may prefer to generate actual ZK components instead of just ZUL markup.

Use Case 3: Converting Source Data into ZK Components

This use case is similar to the previous one, but instead of generating ZUL content, this approach creates actual ZK components based on the FormModel.

This method allows greater flexibility, as developers can manipulate and interact with form components dynamically in Java. Unlike ZUL, which is just markup, ZK components provide direct programmatic control.

Sample generating components

Component zkComponents = formModel.toComponents(new DemoFormbuilderNodeRenderer());
host.appendChild(zkComponents);

Now that we have seen multiple ways to construct a form, the next step is deciding whether to generate ZUL or Java objects.

Generating ZUL or Java Objects

As demonstrated in the previous two use cases, once a FormModel is created, you can choose between:

  • Generating ZUL content (as a string)
  • Generating a set of ZK components (Java objects)

Each approach has its advantages:

ZUL:

  • More readable
  • Can be modified in a text editor

Components:

  • Can be manipulated directly in Java
  • Allows the application of a Composer on-the-fly

Choosing the right approach depends on your use case. If your form structure is mostly static, ZUL might be the better choice. If your form needs dynamic interactions or programmatic modifications, generating Java components is more suitable.

Add More Field Templates

ZK Form Builder comes with built-in field templates, but you may need to define custom templates to fit your specific project requirements.

If your project is a Maven project, you can simply create a ZUL file under /src/main/resources/template, and the form builder will automatically recognize and use it as a field template.

Important Notes:

  • Do not use the same file name as a built-in template, or your custom template will not take effect.
  • Custom templates allow you to extend the form builder’s capabilities while keeping the form rendering logic flexible.

With the ability to define custom templates, developers can further refine and customize their form-building experience.

Getting Started

I hope you find this article interesting. To try it out, you can check the source code and download the JAR from GitHub. Let us know what you think -your feedback will help us refine and improve the tool further.

Going forward

Currently, the ZK Form Builder requires you to manually parse your JSON data since it accepts arbitrary JSON without a predefined format. As a result, we cannot provide a built-in converter for this case, which may make form building less convenient.

To improve this, we are considering adding default parsers and converters for common schemas, such as JSON Schema. This would eliminate the need for manual parsing and conversion to a FormModel, making the process more efficient.

We’d love to hear your feedback — leave a comment in the comment section below or email us at info@zkoss.org and let us know which schemas or tools would be most useful to you!

Feedback



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.