This content originally appeared on DEV Community and was authored by Explorer
1. Overview
While Joget's Form Builder is excellent for visual design, there are advanced scenarios where you need to generate form definitions programmatically. This is typically done when a form's structure is dynamic or based on an external metadata source (e.g., a database table, a configuration list, or another Joget list).
This blog post analyzes a powerful BeanShell/Groovy script designed to run within Joget's server-side tools. It reads form field definitions from a FormRowSet (or similar data source) and constructs a complete Joget Form Definition JSON, finally saving it to the App Definition.
2. How It Works
The script operates by constructing the complete JSON object that defines a Joget Form, adhering strictly to the internal schema used by the platform.
-
⚙️ Data Source: The script assumes field metadata (ID, Label, Class Name) is available in the
rowsvariable (aFormRowSet). -
⚙️ Field Construction: It iterates over the
rows. For each entry, it creates a string representation of a JSON object for a single form element, ensuring theclassName(field type) andproperties(ID and Label) are correctly inserted. -
⚙️ JSON Aggregation: All individual field JSONs are placed into a
JSONArray(fields). This array is then inserted as the content of the Form's mainColumnelement. -
⚙️ Form Saving: Finally, the fully assembled JSON is wrapped in a
FormDefinitionobject. The script uses theAppServicebean to callcreateFormDefinition, making the new form instantly available in the App Designer.
3. Full Code
This code is typically executed within a Process Tool using the BeanShell/Groovy language or in a Form/Datalist Binder script where the rows variable is populated.
import java.util.Collection;
import org.joget.apps.app.model.AppDefinition;
import org.joget.apps.app.model.FormDefinition;
import org.joget.apps.app.service.AppService;
import org.joget.apps.app.service.AppUtil;
import org.joget.apps.form.model.FormRow;
import org.joget.apps.form.model.FormRowSet;
import org.joget.commons.util.LogUtil;
import org.json.JSONArray;
import org.json.JSONObject;
// Get form metadata from request or script tool properties
String formDefId = formData.getRequestParameter("form_def_id");
String formName = formData.getRequestParameter("form_name");
String formTableName = formData.getRequestParameter("form_table_name");
// Example: Assume 'rows' is a FormRowSet containing field configurations
// FormRowSet rows = ...
try {
JSONArray fields = new JSONArray();
// Loop through the source data (e.g., field definitions)
for (FormRow row : rows) {
String fieldId = row.getProperty("field_id");
String fieldLabel = row.getProperty("field_label");
// Must be a valid Joget Form Element class name (e.g., org.joget.apps.form.lib.TextField)
String className = row.getProperty("field_type");
JSONObject formElement;
// Build the JSON structure for a single form element
formElement = new JSONObject("{\n" +
" \"className\" : \"" + className + "\",\n" +
" \"properties\": {\n" +
" \"controlField\": \"\",\n" +
" \"id\": \"" + fieldId + "\",\n" +
" \"label\": \"" + fieldLabel + "\",\n" +
" \"permissionHidden\": \"\",\n" +
" \"readonly\": \"\",\n" +
" \"readonlyLabel\": \"\",\n " +
" \"size\": \"\",\n" +
" \"validator\": {\n" +
" \"className\": \"\",\n" +
" \"properties\": {}\n" +
" },\n" +
" \"value\": \"\",\n" +
" \"workflowVariable\": \"\"\n" +
" }\n" +
"}");
fields.put(formElement);
}
// Embed all generated fields into the main Form structure
JSONObject form = new JSONObject("{\n" +
" \"className\": \"org.joget.apps.form.model.Form\",\n" +
" \"elements\": [{\n" +
" \"className\": \"org.joget.apps.form.model.Section\",\n" +
" \"elements\": [{\n" +
" \"className\": \"org.joget.apps.form.model.Column\",\n" +
" \"elements\":" + fields.toString() + ",\n" +
" \"properties\": {\"width\": \"100%\"}\n" +
" }],\n" +
" \"properties\": {\n" +
" \"id\": \"section1\",\n" +
" \"label\": \"Dynamic Fields Section\"\n" +
" }\n" +
" }],\n" +
" \"properties\": {\n" +
" \"description\": \"Dynamically generated form.\",\n" +
" \"id\": \"" + formDefId + "\",\n" +
" \"loadBinder\": {\n" +
" \"className\": \"org.joget.apps.form.lib.WorkflowFormBinder\",\n" +
" \"properties\": {}\n" +
" },\n" +
" \"name\": \"" + formName + "\",\n" +
" \"noPermissionMessage\": \"\",\n" +
" \"permission\": {\n" +
" \"className\": \"\",\n" +
" \"properties\": {}\n" +
" },\n" +
" \"postProcessor\": null,\n" +
" \"postProcessorRunOn\": \"create\",\n" +
" \"storeBinder\": {\n" +
" \"className\": \"org.joget.apps.form.lib.WorkflowFormBinder\",\n" +
" \"properties\": {}\n" +
" },\n" +
" \"tableName\": \"" + formTableName + "\"\n" +
" }\n" +
"}");
// Save the new Form Definition to the current App
FormDefinition formDefinition = new FormDefinition();
formDefinition.setJson(form.toString());
formDefinition.setId(formDefId);
formDefinition.setName(formName);
formDefinition.setTableName(formTableName);
AppService appService = (AppService) AppUtil.getApplicationContext().getBean("appService");
AppDefinition appDef = AppUtil.getCurrentAppDefinition();
Collection errors = appService.createFormDefinition(appDef, formDefinition);
// Optional: Log errors if form creation failed
if (errors != null && !errors.isEmpty()) {
LogUtil.warn("FormCreator", "Errors encountered while creating form: " + errors.toString());
}
} catch (Exception ex) {
LogUtil.error("FormCreator", ex, "Cannot Create Form");
}
`
4. Example Use Cases
- âś… Dynamic Survey Generation: Create different forms instantly based on survey questions stored in a master configuration list.
- âś… Automated Integrations: Automatically generate forms that mirror the structure of an external API or third-party database table, minimizing manual development work.
- âś… User-Defined Forms: Allow specific power-users to define the fields they need in a secondary Joget list, then use this script to generate the final functional form.
5. Customization Tips
- đź’ˇ Field Type Mapping: Use a map structure in your BeanShell script to translate simple data types (e.g.,
"TEXT") from your sourcerowsinto the necessary full Java Class Names (e.g.,"org.joget.apps.form.lib.TextField"). - đź’ˇ Adding Complex Properties: For field types like Select Boxes, dynamically add the
optionsoroptionsBinderproperties to theformElementJSON to ensure the new field is fully functional upon creation. - đź’ˇ Metadata Refresh: If you use this script to update a form, use
appService.updateFormDefinitioninstead ofcreateFormDefinition.
6. Key Benefits
- 🚀 Metadata-Driven Design: Decouples form structure from application code, making forms easier to manage and update.
- 🚀 Consistency: Ensures all generated forms follow a consistent structure (e.g., using the same default binders and field properties).
- 🚀 Extensibility: Enables the creation of complex applications where form fields are determined by business rules or configuration, not just static design.
7. Security Note
đź”’ Access Control: Since this script can alter the core application definition, it must be carefully permissioned. It is best used in a workflow process tool that runs under the secure system user account or is triggered only by application administrators. Avoid exposing this logic directly in front-end form validation or client-side scripts.
8. Final Thoughts
Leveraging BeanShell to dynamically manipulate Joget's JSON configurations is the pinnacle of advanced Joget development. It unlocks the ability to build flexible, configuration-driven solutions that are resilient to changes in business requirements.
This content originally appeared on DEV Community and was authored by Explorer
Explorer | Sciencx (2025-11-16T10:02:36+00:00) 🛠️ Dynamic Joget Form Generation Using BeanShell Scripting. Retrieved from https://www.scien.cx/2025/11/16/%f0%9f%9b%a0%ef%b8%8f-dynamic-joget-form-generation-using-beanshell-scripting/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.