Warning: Undefined variable $current_id in /home/ci574801/nectain.com/www/wp-content/themes/nectain/single-documentation.php on line 3
Updated 1 year ago

Constructor

The Document Builder allows configuring the form for filling out a particular type of document using a graphical interface. It enables adding attributes to the form for data entry and customizing the appearance of these fields, controlling access to these attributes, and their display for different roles.

The constructor mode consists of several stages that allow configuring custom forms using a graphical interface:

  • Designer
  • Access
  • Mandatory Fields
  • Preview
  • Script

Designer

In the "Designer" mode of the document constructor, the layout of the future document form is created.

On the left side, there is the attribute panel, which includes attributes that can be included in the document: standard attributes in the "Document" folder and custom ones grouped in folders corresponding to the folders in the "Attribute Library." Attributes that are not added to folders are located in the "Ungrouped Attributes" folder. There is a search field above the attribute panel to search for the desired attribute by name. Attributes are added to the form by dragging them from the attribute panel onto the form. Actions can be undone or redone using the respective "Undo" and "Redo" buttons.

To arrange attributes on the form, the "Layout" controls are used, including tabs and sections.

The "Tab" control (under "Layout") organizes attributes on the document form into tabs. After placing the "Tab" control on the form, additional tabs can be created inside it, where attributes can be placed, and the tab names can be changed. By default, one tab is created.

The "Section" control (under "Layout") allows grouping elements into sections. After placing the "Section" control on the form, attributes can be placed inside it. When the width of the section is changed, the width of all attributes inside the section changes accordingly.

The arrangement of attributes on the document form can also be adjusted by dragging attributes up or down within the form.

When constructing a document, attributes from different groups can be used to avoid duplicating attributes.

Note: When adding the same attribute to the form, it is duplicated, and subsequently, when filling out the document, the values are duplicated.

On the right side of the document form, there is the "Settings" panel for the selected form element. Each attribute has its own set of settings:

  • Disabled: ability to restrict access to the attribute.
  • Invisible: ability to hide the attribute.
  • Label: name of the attribute on the document form (by default, it is the attribute name from the library).
  • Label Width: permissible label size (text with the attribute name).
  • Label Position: selection of label placement on the form - top, right, or left.
  • Width: attribute width on the form. The standard form size is 24 units wide. By default, the attribute spans the entire width of the form.
  • Left Margin: margin from the left of the selected attribute.
  • Line Break: all elements following the selected one will be moved to the next line.
  • Height: adjustment of the field height - automatically 1 unit or specify the field size in percentages.
  • Placeholder: text displayed when the attribute value is not filled in.
  • Default Value.

Additionally, the constructor displays attribute parameters that cannot be changed:

  • Code
  • Name
  • Type
  • Data Object
  • Generate Script
  • Element ID

In the designer, there is the option to open the settings form for custom attributes. Select the custom attribute on the form and click on "Open Attribute" in the settings.

Access

For each attribute, you can configure its access level depending on the user's role or document state. To do this, in the constructor mode, you need to open the "Access" tab.

To change access, select the "State" (default is "All States") and "Role" (default is "All Roles"). Then choose the attribute, section, or tab, and when hovering over it, the access settings will be displayed.

The possible access options are described in the table:

Button Name Description
Inherit Inherits access from the top-level attribute of the form. For example, if several attributes are placed inside a "Section," you can set access to the section, which will be inherited by all attributes inside.
Hide No access to the field, it is not displayed when viewed.
View The field is displayed for viewing without the ability to edit.
Edit The field is available for editing.

When selecting an attribute, the "Access Rules" panel is displayed on the right. The panel contains all information about the access levels to this attribute for all roles and document states. When selecting an attribute, the settings for that attribute will be displayed.

Mandatory Fields

For each attribute, you can configure mandatory filling rules depending on the document state or action. To do this, in the constructor mode, you need to open the "Mandatory" tab.

To change the mandatory rule, select the "State" (default is "All States") and "Action" (default is "Any Action"). Then choose the attribute, and when hovering over it, the mandatory settings will be displayed.

The options for mandatory rules are described in the table:

Button Name Description
Inherit Inherits access from the top-level attribute of the form. For example, if several attributes are placed inside a "Section," you can set the mandatory status for the section, which will be inherited by all attributes inside.
No The attribute is not mandatory to fill.
Yes The attribute is mandatory to fill.

When selecting an attribute, the "Mandatory Rules" panel is displayed on the right. The panel contains all information about the mandatory rules for this attribute for all roles and document actions. When selecting an attribute, the settings for that attribute will be displayed.

Preview

In the "Preview" mode of the constructor, you can review the created document form and its capabilities under defined states and roles of the document type.

When selecting a "State" or "Role," the corresponding form settings will be displayed.

Script

In the "Script" mode of the constructor, you can create extensions to the form's behavior using customized logic. Scripts use the JavaScript programming language and are executed by the browser as the main code of the application.

To create scripts, you need some basic knowledge of JavaScript:

- Basics of the language (expressions, statements, functions, variables, etc.)

- JavaScript modules

- Asynchronous functions

Additionally, to make requests to the server, familiarize yourself with the UnityBase documentation, especially with the @unitybase/ub-pub module, the connection object, and the ClientRepository class.

The system provides templates for specific actions based on attributes. To use them (copy to the clipboard), in the designer (for document types, task forms, and other elements of the system), select the attribute and click "Generate Script," then select the action.

Module:

Each form script must be a CommonJS module, meaning it must contain a line like this:

```javascript
module.exports = {
// ...
}
```

Note: Any script is written inside the construct:

```javascript
module.exports = {
}
```

Event Interaction:

Interaction with form events is event-driven, and the object exported by the module must contain event handlers as properties. For example:

```javascript
module.exports = {
loaded() {
console.log('Inside "loaded" event handler for the form!')
}
}
```

A script can have only one module.exports. If one script needs to define two or more events, they are listed in one module.exports, separated by a comma. Do not define multiple module.exports - it will not work.

Events:

The key name in the exported object (not to be confused with the function name) determines which event the function will respond to. The event-to-function binding is based on naming conventions.

Each event handler can be asynchronous or return a promise (not required, but can be if necessary; in this case, the code will wait for the event handling to finish).

Sometimes the same event is handled by multiple handlers. For example, there may be a specific event handler for the action action_beforeExecute_action1 and a general event handler for action_beforeExecute. This is not a common situation, but if it happens, the general event handler will be executed before the specific event handler.

Event Argument:

Each event handler accepts exactly one argument, conventionally named event. If the handler does not use the parameter, do not specify it. However, if the handler uses the event argument, name it event.

You can "require" service scripts, as in any client module UB.

```javascript
const UB = require('@unitybase/ub-pub')
module.exports = {
// ...
}
```

Note: If you use external scripts, you are responsible for maintaining the form script when the external module changes (and sometimes they may have critical changes), use it accordingly.

The event argument capabilities depend on the form object. For example, for a BPM task form, the event will contain the task property, and for the Scriptum document, it will contain the document property. Tasks related to Scriptum Document will have task and document properties.

This is also a configuration point; for extensive integration, you can develop an additional tool to access objects in your custom model and make it visible within form scripts.

Each such property is called an object access tool as it provides tools for getting or setting values for the attributes of the corresponding object.

Object Access API:

- getAttribute: retrieves the value of a custom attribute (from the attribute library, not the object attribute).

```javascript
event.document.getAttribute('color')
```

- getNativeAttribute: retrieves the value of a configured attribute. "Native" denotes an entity attribute, not an attribute from the attribute library.

```javascript
event.document.getNativeAttribute('docNumber')
```

- setAttribute: changes the value of a custom attribute. To clear the value, set it to null.

```javascript
event.document.setAttribute(
'fullName',
event.document.getAttribute('firstName') + ' ' + event.document.getAttribute('lastName')
)
```

- setNativeAttribute: changes the value of a native attribute. To clear the value, set it to null. "Native" denotes an entity attribute.

```javascript
event.document.setNativeAttribute('docNumber', '123')
```

Some object access tools may provide additional methods. For example, the Scriptum Document object access tool provides the following methods:

- state: returns the code of the current document state.

```javascript
if (event.document.state === 'draft') {
// It's a draft!
}
```

- userHasRole: checks if the document user has a role (not UB), by its code.

```javascript
if (event.document.userHasRole('author')) {
// It's the document author!
}
```

- getParticipants: returns information about document participant roles.


```javascript
const participantsOfResponsibleRole = event.document.getParticipants('responsible')
```

- removeParticipant: removes any participant from a document role.


```javascript
event.document.removeParticipant('responsible', participantID)
```

- addParticipant: adds a participant to a document role.


```javascript
event.document.addParticipant('responsible', participantID)
```

- getCurrentUserRoles: returns the current document user's roles as an array of strings.


```javascript
const userRoles = event.document.getCurrentUserRoles()
```

Global Form Events:

Initialization form events:

- inited

- loaded

These are two similar events; the only difference is that initied is called only on the first data load of the form, while loaded is called every time the form is loaded (the user can use the "Refresh" toolbar button to reload the form).

Form Saving Events:

- beforeSave

- saved

Inside beforeSave, it's possible to cancel the saving:


```javascript
module.exports = {
beforeSave(event) {
if (!!event.document.getAttribute('hasCategory') && !event.document.getAttribute('categoryID')) {
// "categoryID" must be specified if "hasCategory" toggle is toggled
event.cancelSave()
}
}
}
```

Action Events:

If the event is "before" and "after":

- action_beforeExecute

- action_beforeExecute_<actionCode>

- action_executed

- action_executed_<actionCode>

An event without an action code suffix will be called for any action, while events with an action code suffix will be called only for specific actions.

All events have an additional property - actionCode, which is used for universal action event handlers (without the action code in the event name).

In "before" handlers, the following additional methods are also available:

- cancelAction: allows canceling the action. Used for checks.

- skipStandardConfirmDialog: calling this method means "Do not show any confirmation before the action." Used in cases where a user interface is called inside the handler and the standard confirmation needs to be overridden. Most likely, it will be necessary to use an asynchronous event handler that returns a confirmation message after the user confirms the action in the user interface. Add the async keyword:

```javascript
const customUI = require('path_to_my_custom_ui_module')
module.exports = {
async action_beforeExecute_approve(event) {
const confirmResult = await customUI.approveActionDialog()
if (!confirmResult) {
event.cancelAction()
}
}
}
```

Attribute Events:

Attribute events are variations of the general attributeChanged event:

- <dataObject>_attributeChanged

- <dataObject>_nativeAttributeChanged

- <dataObject>_attributeChanged_<attributeCode>

- <dataObject>_nativeAttributeChanged_<attributeCode>

As seen from the event name template, each event variant filters events by data object (e.g., task or document), attribute type (custom - from the attribute library, or native - entity attribute), and attribute code.

The event object itself contains properties specific to attributeChange events:

- dataObject

- attributeCode

- attributeKind

- value

- oldValue - previous value


```javascript
module.exports = {
document_attributeChanged(event) {
if (event.attributeCode === 'firstName' || event.attributeCode === 'lastName') {
event.document.setAttribute(
'fullName',
event.document.getAttribute('firstName') + ' ' + event.document.getAttribute('lastName')
)
}
}
}
```

This result can be achieved with another approach - instead of one event handler for all document attribute changes with logic inside that analyzes which attribute has changed, the same goal can be achieved by having two separate event handlers - one for each attribute:


```javascript
module.exports = {
document_attributeChanged_firstName(event) {
event.document.setAttribute(
'fullName',
event.value + ' ' + event.document.getAttribute('lastName')
)
},
document_attributeChanged_lastName(event) {
event.document.setAttribute(
'fullName',
event.document.getAttribute('firstName') + ' ' + event.value
)
}
}
```

In the latter variant, the code is cleaner. This approach is recommended.

Changing Form Element Properties:

Form scripts allow changing the form layout during execution:

- Change the property of a form element (nodes)

- Change form elements (nodes), necessary rules supporting it (document execution forms and tasks)

- Change form elements (nodes) accessRules for forms supporting it (e.g., document forms)

The event object has a special property form, which contains a special object with the following methods:

- setNodeProperty

- setNodeRequiredRule

- setNodeAccessRule

All these methods accept a nodeId as the first argument, key as the second, and value as the third.


```javascript
module.exports = {
document_attributeChanged_country(event) {
// Do not allow changing 'city' (nodeId = 10), unless country value is set
event.form.setNodeProperty(
10,
'disabled',
!event.value
)
}
}
```

Debugging Scripts:

Outputting information to Console.log is displaying information in the browser console: F12, Console tab.

There are several ways to debug form scripts. They all require creating a document and testing it:

- Place a debugger statement in the scripts; they will open DevTools in the browser (F12 key) and try:


```javascript
module.exports = {
document_attributeChanged_firstName(event) {
debugger
event.document.setAttribute(
'fullName',
event.value + ' ' + event.document.getAttribute('lastName')
)
}
}
```

- Use console.debug:


```javascript
module.exports = {
document_attributeChanged_firstName(event) {
console.debug('document_attributeChanged_firstName event: %j', event)
event.document.setAttribute(
'fullName',
event.value + ' ' + event.document.getAttribute('lastName')
)
}
}
```

- Use breakpoints: open DevTools in the browser, find the script, hint - look under clientRequire/models/cust/public/designedForms, depending on the environment, the model name may not be "cust".

When working with directories, IDs of directory values are passed and returned. For a list of directory values with multiple selection - use square brackets (e.g., [3000000001781, 3000000001748]).

Skip to content