Scripting Forms
Overview
In Servoy, each form has an associated JavaScript (JS) file, which governs its behavior at runtime. This file defines custom methods, handles events, and interacts with the form's base API, giving developers full control over UI elements and data manipulation.
Form at Design Time
At design time, a form represents a visual layout defined in the Servoy IDE. Developers configure UI components, data bindings, and form properties. This design-time form is connected to the JS file, where functionality is scripted to respond to user actions, control form behavior, and handle data transactions. By separating design and logic, Servoy ensures maintainability and clear structure in applications.
Form as a Runtime Object
At runtime, the form becomes an object with a base API, which allows developers to control components, manage data, and trigger custom logic. This API can be extended using the form’s JS file, allowing developers to implement custom behaviors, manage user interactions, and define dynamic data logic.
Encapsulation in Form JS
The form’s JS file supports encapsulation, offering:
Public methods/variables: Accessible across the entire solution, allowing interactions with other forms or modules.
Private methods/variables: Restricted to the form itself, ensuring internal logic is hidden and modular.
Protected methods/variables: Available within the form and any inherited forms, ensuring reusable and secure methods in inherited structures.
Form Methods
In Servoy, a form method is a custom JavaScript function defined within a form's script that encapsulates specific functionality or business logic. Unlike form events, which are automatically triggered by user actions or form lifecycle changes (e.g., onLoad, onShow), form methods are explicitly called by the developer to perform particular tasks. They promote code reusability, organization, and maintainability by allowing you to encapsulate frequently used logic within dedicated functions. These methods can handle tasks such as data manipulation, validation, UI updates, integrations, and more. They are defined within the form's script and can be invoked from event handlers, other methods, or even from different forms if designed as global methods.
When and How to Use Form Methods
When to Use:
Reusability: When you have logic that needs to be executed from multiple places within the form.
Organization: To keep event handlers clean by delegating complex logic to separate methods.
Maintenance: Easier to update and manage specific functionalities without affecting unrelated code.
Encapsulation: To encapsulate business logic, making the codebase more modular and understandable.
How to Use:
Define the Method: Within the form's script, define a function with a clear and descriptive name.
Call the Method: Invoke the method from event handlers, other methods, or even from different forms if necessary.
Pass Parameters: If needed, pass parameters to the method to make it more flexible and adaptable to different scenarios.
Return Values: Methods can return values to be used by the caller, enabling further processing or decision-making.
Common Use Cases with Examples
Data Manipulation (CRUD Operations)
Use Case: Handling Create, Read, Update, and Delete operations on records within a form.
Example: Saving a Record with Validation
Explanation:
saveRecord
Method: This method first calls validateForm to ensure data integrity. If validation passes, it attempts to save the data using databaseManager.saveData(foundset). It then provides user feedback based on the success of the operation.validateForm
Method: Checks that required fields are filled and that the email address is in a valid format.validateEmail
Method: Uses a regular expression to verify the email format.
When to Use: When implementing a save functionality that requires data validation before persisting to the database.
Data Retrieval and Filtering
Use Case: Searching for records based on user input or applying specific filters to display subsets of data.
Example: Searching for Customers by Name
Explanation:
searchCustomers
Method: Initiates a find mode on the foundset, sets the search criteria using wildcards for partial matching, and performs the search. It then informs the user about the number of records found.
When to Use: When implementing search functionality to allow users to find records based on specific criteria.
Form Initialization and Reset
Use Case: Preparing the form with default values when it's loaded or resetting the form to its initial state.
Example: Initializing a New Customer Form
Explanation:
initializeNewCustomer
Method: Checks if the current record is new. If so, it sets default values for date_created and status, and ensures that certain UI elements are enabled.
When to Use: When setting up the form for creating new records, ensuring that default values are populated, and UI elements are appropriately configured.
Data Validation
Use Case: Ensuring that the data entered by the user meets specific criteria before performing operations like saving.
Example: Validating Order Quantity
Explanation:
onDataChangeQuantity
Method: Attached to the onDataChange event of the quantity field. It ensures that the entered quantity is at least 1. If not, it shows a warning and rejects the change.
When to Use: When implementing field-specific validations to maintain data integrity.
Business Logic Execution
Use Case: Performing complex calculations, processing workflows, or handling specific business rules within the application.
Example: Calculating Total Order Amount
Explanation:
calculateTotalAmount
Method: Iterates through related order line items, calculates the total by multiplying quantity and unit price for each line, and updates the total_amount field.
When to Use: When implementing calculations or processing that depend on multiple data points or related records.
Best Practices for Using Form Methods
Descriptive Naming: Name methods clearly to indicate their purpose (e.g., validateForm, saveRecord).
Single Responsibility: Each method should perform a single, well-defined task to enhance readability and maintainability.
Parameterization: Use parameters to make methods flexible and adaptable to different scenarios.
Error Handling: Incorporate robust error handling within methods to manage unexpected situations gracefully.
Reusability: Design methods to be reusable across different parts of the form or even across different forms if applicable.
Documentation: Comment your methods to explain their purpose, parameters, and return values for better understanding and future reference.
Modularity: Keep methods modular to allow easy testing, debugging, and updating without affecting unrelated functionalities.
Form Variables
A form variable in Servoy is a local variable that belongs to a specific form and can be used to store and manage data at the form level. Form variables are typically used to manage temporary data, control form behavior, and interact with form elements, but they are not tied to any database column. They provide a convenient way to hold values specific to a form without affecting the underlying data model.
Characteristics of a Form Variable
Scope: A form variable is limited to the form where it is defined.
Lifecycle: It exists as long as the form is loaded and is reset when the form is reloaded or closed.
Type: Form variables can have various data types (String, Number, Date, etc.), depending on how they are defined.
When to Use a Form Variable
Form variables are useful in scenarios where you need to:
Store temporary data that does not need to be persisted in the database.
Control the state or behavior of the form (e.g., toggle UI elements or track form status).
Hold user input or selections before saving them to the database.
Implement complex logic or calculations without cluttering the database structure.
Common Use Cases with Examples
Form Variable as a Dataprovider
Form variables can be used as dataproviders in Servoy. A dataprovider in Servoy is essentially a data source for UI elements like text fields, checkboxes, and combo boxes, allowing them to display and interact with data. Typically, dataproviders are database fields, but form variables can also be assigned as dataproviders when you want to display or bind non-persistent data in the UI.
To use a form variable as a dataprovider for a UI element, follow these steps:
Create a Form Variable and define its name, data type (String, Number, Boolean, etc.), and optional initial value.
Assign the Variable as a Dataprovider:
Select the form element (e.g., a text field or label) that you want to bind to the form variable.
In the Properties section, under Dataprovider, choose the form variable as the dataprovider for that element.
Update the Form Variable Programmatically:
You can read or modify the form variable in your form methods, and the UI element will automatically update based on the variable's value.
Example: Displaying Non-Persistent Data Form variables as dataproviders are useful when you want to display information that doesn't come from the database and doesn't need to be saved.
Use Case: You have a calculated or temporary value, like a subtotal, that you want to display on the form without saving it to the database.
How to Use:
Create a form variable called
subtotal
of typeNumber
.Set
subtotal
as the dataprovider for a label or text field on the form.When the
calculateSubtotal()
method is called and the subtotal variable is updated, the UI element will reflect the new value.
Storing Temporary UI State
Form variables are often used to control the state of UI elements, such as enabling/disabling fields or showing/hiding certain sections of a form.
Use Case: A form variable is used to control whether a form field is editable or not, based on the current user’s role or the status of the record.
Example:
How to Use:
Create a form variable called
isEditMode
of typeBoolean
.Use this variable in the
toggleEditMode()
method to control whether form elements likemyTextField
are enabled or disabled.The form switches between
view
andedit
modes when a user clicks a button.
Holding User Input Before Saving
Form variables are useful for holding user input, such as search terms or selections, before the data is processed or saved to the database.
Use Case: A form variable holds a user’s search term before running a search query.
Example:
How to Use:
Create a form variable called
searchTerm
of typeString
.Use this variable to store the user’s input from a search field.
When the user clicks a
Search
button, theperformSearch()
method is triggered, using the value ofsearchTerm
to filter records.
Toggling UI Visibility
Form variables can be used to show or hide certain elements on a form based on user interactions or conditions.
Use Case: A form variable is used to toggle the visibility of a "details" panel when a user clicks a button.
Example:
How to Use:
Create a form variable called
showDetails
of typeBoolean
.Use this variable to determine whether a panel or section of the form (e.g.,
detailsPanel
) is visible or hidden.Attach the
toggleDetails()
method to a button to toggle the visibility of the panel.
Tracking Status or Workflow
Form variables can be used to track the status of a process or workflow, such as a multi-step form where the user progresses through various stages.
Use Case: A form variable is used to track the current step in a multi-step wizard.
Example:
How to Use:
Create a form variable called
currentStep
of typeNumber
.Use this variable to track which step the user is currently on in a multi-step process.
The
nextStep()
method increments the step and updates the form's UI accordingly.
Performing Temporary Calculations
Form variables can be used to store intermediate values during calculations, such as subtotals or temporary values that are not saved to the database.
Use Case: A form variable is used to store a calculated subtotal in a sales form before the total is saved.
Example:
How to Use:
Create a form variable called
subtotal
of typeNumber
.Use the
calculateSubtotal()
method to calculate and display the subtotal for an order, without saving it to the database.The form variable can be used to temporarily hold this value for further processing.
Form Events
A form event in Servoy is a specific type of method that is triggered automatically by the Servoy framework when certain actions or changes occur in a form. These events are tied to the form’s lifecycle (e.g., loading, showing, hiding) or interactions (e.g., user selecting records, data changes). Form events are particularly useful for handling initialization, clean-up, and reacting to changes in the form’s data or state.
Common Types of Form Events
onLoad: Triggered when the form is loaded for the first time (before it's shown).
onShow: Triggered each time the form is shown (e.g., when switching between forms or tabs).
onHide: Triggered when the form is about to be hidden (e.g., before navigating away from the form).
onRecordSelection: Triggered when a user selects a different record in the form.
For more details, see the Form Events documentation.
When to Use Form Events
You use form events when you need to perform actions based on the form’s lifecycle or user interactions. Some common scenarios include:
Initializing form components or setting default values when the form is loaded or shown.
Saving data or cleaning up resources when a form is hidden or closed.
Reacting to user input when they select different records or modify data.
Performing custom validation or calculations when specific fields are changed.
Common Form Events and Use Cases with Examples
onLoad Event
The onLoad event is triggered the first time the form is loaded into memory. It is commonly used to initialize form variables, configure UI elements, or load data into the form.
Use Case: Initialize certain form elements or variables when the form is loaded.
Example:
How to Use:
You can set the
onLoad
event in the form properties, and it will be called automatically when the form is first loaded.This event is typically used to perform one-time initialization tasks.
onShow Event
The onShow event is triggered every time the form is shown. This can happen when switching between forms or tabs or when reloading the form. This event is useful for refreshing data, resetting the UI, or showing specific information to the user.
Use Case: Reload data from the database or reset UI components each time the form is displayed.
Example:
How to Use:
Assign this event in the form properties under
onShow
.You can use the
firstShow
parameter to differentiate between the first time the form is shown and subsequent displays.This event is ideal for refreshing or reloading data that might change between displays.
onHide Event
The onHide event is triggered when the form is about to be hidden (e.g., when navigating to another form or closing a form). It’s useful for saving data, confirming navigation, or performing clean-up tasks.
Use Case: Prompt the user to confirm navigation if there are unsaved changes.
Example:
How to Use:
Set the
onHide
event in the form properties.This event is useful for ensuring data integrity, asking for user confirmation, or cleaning up resources before the form is hidden.
onRecordSelection Event
The onRecordSelection event is triggered every time the user selects a different record in the foundset (the set of records displayed on the form). It’s useful for updating form fields or performing actions specific to the selected record.
Use Case: Display additional information when a user selects a different record.
Example:
How to Use:
Assign this event to the form, and it will trigger automatically when a user selects a new record.
This is particularly useful when displaying master-detail forms or updating related fields based on the selected record.
Advanced Features
Form Instances
A form instance in Servoy refers to an individual, dynamically created version of a form. Normally, when you design a form in Servoy, it’s a single reusable template that can display multiple records. However, form instances allow you to create multiple independent versions of the same form at runtime, each with its own unique state, data, and UI elements. This is useful in scenarios where you need multiple copies of a form to be shown simultaneously, but with different data or configuration.
Key Characteristics of Form Instances:
Each form instance is treated as a separate object, allowing you to manipulate it independently.
Form instances can have different foundsets (sets of records), methods, and properties, even though they share the same form design.
This allows you to work with multiple datasets or configurations on the same form template.
When to Use Form Instances: Form instances are useful when:
You need to display the same form multiple times, but with different datasets or configurations (e.g., side-by-side views of data).
You want to work with different foundsets on the same form.
You need pop-up windows or dialogs that are based on the same form but with different parameters.
You want to maintain independent states for each version of the form, such as filters, selections, or user interactions.
In Servoy, application.createNewFormInstance is a method used to create a new instance of a form at runtime. This new form instance behaves independently of the original form and can have its own data, UI state, and behavior. This method is especially useful when you want to display the same form multiple times but with different datasets or UI configurations, such as in pop-up dialogs, side-by-side comparisons, or for managing multiple editing sessions.
Key Points About application.createNewFormInstance
:
Creates an Independent Instance: The newly created form instance is independent of the original form. It is effectively a clone of the form, but it can operate with a different foundset or with modified UI components.
Maintains Structure: The new form instance keeps the structure, layout, and components of the original form. However, its behavior and data can be customized for each instance.
Does Not Duplicate Logic: It doesn't duplicate the underlying logic or code. It simply provides a unique instance to work with separately.
Naming: Each form instance must be given a unique name when it's created, so that it can be referenced individually during runtime.
Example
Use Case: You have a list view form displaying multiple records (e.g., a customer list), and you want to allow users to open multiple non-modal dialog windows showing the details of individual records. Each dialog will display details of a selected record in a detail view, and the user can open several dialog windows at the same time, independently editing different records.
In this use case, we have three forms:
dialog_base
: An abstract form that serves as the base form, allowing other forms to inherit its behavior. It contains a generic method to open instances of itself in dialog windows.orders_detail
: A detailed view form that extends dialog_base and is used to show detailed information about individual orders.list_view
: A form that displays a list of orders in a data grid, and when a user double-clicks an order, it opens a detailed view of that order in a non-modal dialog using the openInstance method from dialog_base.
The goal is to provide a user interface where:
A list of order IDs is shown in a list view (using
list_view
form).When a user double-clicks on any order in the list, the detailed information for that order opens in a non-modal dialog (using the orders_detail form).
Each dialog can open independently, allowing multiple order details to be viewed or edited simultaneously.
Forms Breakdown:
dialog_base
Form (Abstract Form) This form is the foundation for opening instances of forms as dialogs. It provides two main methods:openInstance()
: Creates a new instance of the form if it doesn’t exist and then opens that instance using theopen()
method.open()
: Loads the selected record into the form’s foundset and opens it in a dialog window.
orders_detail
Form (Extendsdialog_base
) The orders_detail form is a detail view for displaying and editing order data. It extends dialog_base, meaning it inherits the openInstance() and open() methods to open itself in a dialog. The orders_detail form is tied to the orders table with a separate foundset (namedFoundset set to "separate"), meaning each instance of the form works independently of others.list_view
Form (List View of Orders) The list_view form displays a list of orders in a data grid. When the user double-clicks on an order, it triggers the onCellDoubleClick() method, which opens a detailed view of that order in a non-modal dialog.
In this method:
onCellDoubleClick()
retrieves the selected order record from the list.The
openInstance()
method of theorders_detail
form is called, which opens the order's detailed information in a non-modal dialog.
Full Flow Explanation:
List View Display (
list_view
form):The
list_view
form shows a list of order IDs using a data grid.When the user double-clicks on any order, the
onCellDoubleClick()
method is triggered.
Open Dialog (
orders_detail
form):The
onCellDoubleClick()
method calls theopenInstance()
method from theorders_detail
form (which inherits this fromdialog_base
).The
openInstance()
method creates a new instance of theorders_detail
form for the selected order, ensuring that each dialog window is unique.The
open()
method indialog_base
then loads the selected order record into the form's foundset and opens a non-modal dialog showing the detailed order information.
Multiple Dialogs:
Because each instance is uniquely identified by the order's primary key, users can open multiple dialogs for different orders at the same time.
Each dialog is independent, allowing users to view or edit multiple orders without interfering with each other.
Inheritance
Form inheritance in Servoy is a feature that allows one form to inherit the structure, logic, and behavior of another form, similar to how class inheritance works in object-oriented programming. The inheriting form (known as the subform) can reuse the components, properties, and methods from the parent form, while also adding its own unique elements and functionality. This is a powerful way to create modular, reusable forms and maintain consistent behavior across multiple forms without duplicating code or design.
Key Characteristics of Form Inheritance:
Parent Form: The base form that provides common elements (e.g., fields, buttons) and methods (e.g., validation, event handling). This form can be abstract, meaning it is never used directly but only inherited.
Subform: A form that inherits from the parent form. It can customize or extend the inherited behavior by adding its own elements, overriding methods, or adding new methods.
Inheritance of UI Components: The subform automatically inherits the UI components (such as buttons, fields, and labels) of the parent form but can add or modify them as needed.
Reusability: By using inheritance, you can reduce duplication of UI components and logic, making forms easier to maintain and extend.
Why Use Form Inheritance?
Code Reusability: Common functionality (such as validation, navigation, or event handling) can be placed in a parent form and reused across multiple subforms.
Consistency: Ensures consistent look and behavior across multiple forms, especially useful for creating standardized layouts or workflows.
Simplified Maintenance: If a change is needed in the common functionality, it can be done in the parent form and will automatically apply to all subforms.
Modularity: You can define general-purpose, reusable components in the parent form and specialize them in subforms for different use cases.
For more information on inheritance, see the Form Inheritance Guide.
Custom Design-Time Properties
Custom Design-Time Properties in Servoy are developer-defined properties that allow you to assign additional metadata to a form during development. These properties are available in Servoy Developer but are not directly visible to the end-user or application at runtime. They can be used to store configuration settings, preferences, or other contextual information related to how the form should behave or appear.
Key Points About Custom Design-Time Properties:
Customizable: You can create key-value pairs for any type of configuration or metadata you need for the form.
Design-Time Only: These properties are only accessible during design or development and are not stored or visible at runtime unless explicitly accessed through scripting.
Flexible: You can use them to store different settings, including layout preferences, behavior modes (read-only, editable), themes, or any other relevant metadata that you want to access dynamically.
How and When to Use Custom Design-Time Properties When to Use:
Modular Configuration: To make forms behave differently based on settings that can be controlled by developers during design-time without hard-coding.
Theming/Styling: To apply different visual styles or themes to a form.
Behavior Control: To define how forms behave (e.g., read-only or editable) without changing the logic for each form manually.
Localization: To set language or locale-specific data or translations for a form.
How to Set Custom Design-Time Properties: In Servoy Developer, you can define custom design-time properties directly in the form editor:
Open the form in Servoy Developer.
In the Properties Panel, there is a section for Design-Time Properties.
You can manually add key-value pairs to store your custom properties. For example, you might add:
"theme": "dark"
"mode": "read-only"
"version": "1.0"
How to Access Custom Design-Time Properties in JavaScript: You can retrieve and use custom design-time properties in the form’s JavaScript file using the solutionModel.getForm() method and the getDesignTimeProperty() function.
Syntax:
Example Use Cases for Form's Custom Design-Time Properties:
Theming (Light/Dark Mode)
You can define a custom property like "theme": "dark"
or "theme": "light"
to control the appearance of the form based on the developer's choice. At runtime, you can dynamically change the form’s UI (like colors or styles) based on this property.
Define Property:
In the form's properties panel, add
"theme": "dark"
for a dark theme.
Access and Use in JavaScript:
In this example:
The design-time property
"theme": "dark"
or"theme": "light"
determines how the form should be styled (e.g., background and foreground colors).This allows you to have different versions of the form without modifying the code for each one.
Form Mode (Read-Only or Editable)
You might want to define whether a form is read-only or editable at design time. This can be useful if you have the same form used in different parts of the application where some should allow editing and others should be read-only.
Define Property:
Add
"mode": "read-only"
or"mode": "editable"
in the form’s custom design-time properties.
Access and Use in JavaScript:
In this example:
The form’s mode (read-only or editable) is controlled by the custom design-time property
"mode": "read-only"
or"mode": "editable"
.You can change the behavior of the form’s components (e.g., disabling or enabling input fields) based on the property.
Conditional Behavior or Features
Sometimes you might want to enable or disable certain features in a form based on design-time properties. For instance, you can define whether a feature is enabled by default.
Define Property:
Add "featureXEnabled": true
in the custom design-time properties.
Access and Use in JavaScript:
In this example:
The design-time property controls whether a certain feature (represented by
featureXPanel
) is visible or available on the form.
Last updated