Skip to main content
Version: 8.3

Freedom UI Designer setup area for a custom UI component

Level: advanced
note

This functionality is available for Creatio 8.3.3 and later.

Freedom UI Designer enables no-code creators to build and customize pages without writing code. When developers extended the designer using custom UI components implemented using a remote module, no-code creators could only add those components to a page. Configuring any property of such a component still required a developer to modify the source code of the Freedom UI page directly. This slowed down page iteration and kept no-code creators dependent on development resources for every adjustment.

Since version 8.3.3, Creatio lets developers implement a custom Freedom UI Designer setup area for a custom UI component using a remote module. The setup area can be implemented as part of the same remote module as the UI component itself. A setup area implemented using a remote module behaves the same way as the setup areas of out-of-the-box components:

  1. Opens in Freedom UI Designer when a user selects the component on the canvas.
  2. Reads the current component properties from the Freedom UI page schema.
  3. Saves any changes back to the schema immediately.
  4. Reflects them on the canvas in real time.

It can expose any properties of the component, giving no-code creators full control over the component configuration directly in the designer.

Detailed example: Implement a custom setup area for a UI component implemented using remote module.

To implement a custom setup area, complete the following steps.

1. Create an Angular project

Develop a custom setup area in a dedicated npm package using an external IDE. This example covers the custom setup area development in Microsoft Visual Studio Code.

You can create an Angular project to develop a custom setup area in multiple ways, similarly to creating an Angular project to develop a custom UI component using a remote module. To do this, follow the instructions: Custom UI component implemented using remote module.

The project must include the @creatio/interface-designer library, which provides the API for interacting with the Freedom UI page schema from the setup area. To install the library, run the npm i @creatio/interface-designer command at the Visual Studio Code terminal.

2. Create the setup area component

  1. Run the ng g c view-elements/some-custom-setup-area command in the Visual Studio Code terminal to create an Angular component for the setup area in the project.

  2. Define the setup area constants. Export constants that define the setup area type identifier, property codes used in the Freedom UI page schema, and default property values.

  3. Specify that the setup area component is a view element. Flag the component using the @CrtViewElement decorator and set the type property to the identifier constant of the setup area type.

    Example that registers the setup area component as a view element
    @CrtViewElement({
    selector: 'usr-some-custom-setup-area',
    type: SOME_SETUP_AREA_TYPE_CONSTANT
    })
    export class SomeCustomSetupAreaComponent implements PropertyPanel { }

3. Implement the business logic of the setup area

  1. Add the viewNodeEditor setter to implement the PropertyPanel interface. The PropertyPanel interface defines the contract for the setup area implemented using a remote module. The Freedom UI Designer calls the viewNodeEditor setter when a user selects the component on the canvas.

    Example that implements the PropertyPanel interface
    import { ViewNodeEditor } from '@creatio/interface-designer';

    export interface PropertyPanel {
    /* Provides methods to edit the schema view node for which the property panel
    is opened in the Freedom UI Designer. */
    set viewNodeEditor(nodeEditor: ViewNodeEditor);
    }

    When switching between components of the same type, Creatio reuses the setup area instance and calls the setter again using a new ViewNodeEditor. The implementation must handle multiple setter calls on the same instance correctly and reload state each time. To handle this, delegate initialization to a private async method called from the setter.

    Example that delegates initialization to a private async method
    @Input()
    @CrtInput()
    public set viewNodeEditor(nodeEditor: ViewNodeEditor) {
    this._init(nodeEditor).catch(
    (error) => console.error('Error initializing setup area:', error)
    );
    }
  2. Initialize InterfaceDesignerSchemaService to access view model attributes and data sources.

    Example that initializes InterfaceDesignerSchemaService
    private readonly _schemaEditor = new InterfaceDesignerSchemaService().getSchemaEditor();

    InterfaceDesignerSchemaService provides a getSchemaEditor() method that returns a SchemaEditor with the following sub-editors. The getSchemaEditor() method throws an error if the SchemaEditor is not available. In the designer runtime, this is usually safe when the setup area is instantiated, but keep initialization ordering in mind, especially in tests. The code below shows the SchemaEditor structure.

    Example that shows the SchemaEditor structure
    interface SchemaEditor {
    /* For working with UI elements. */
    viewEditor: SchemaViewEditor;
    /* For working with the data model. */
    modelEditor: SchemaModelEditor;
    /* For working with the view model. */
    viewModelEditor: SchemaViewModelEditor;
    }
  3. Implement the method that reads the current property values from the Freedom UI page schema asynchronously on setup area initialization. Use ViewNodeEditor to read and write property values through the methods described in the table below.

    Method

    Description

    getPropertyValue(propertyName)

    Reads the current value of a property.

    setPropertyValue(propertyName, options)

    Writes a new value to a property.

    Both methods are asynchronous and return promises. Always use await when calling them.

    A property value is a typified object that describes how a value is assigned in the schema. The table below lists the available property value types and how each type appears in the JSON of Freedom UI page schema.

    Type

    Description

    Example of schema JSON

    Constant

    A literal value stored directly in the schema (a string, number, boolean, or object).

    {
    "text": "32",
    "visible": true
    }

    Attribute binding

    A reference to a view model attribute, prefixed using $ in the schema JSON.

    {
    "control": "$Account.Name"
    }

    Resource binding

    A reference to a localization string, prefixed using $Resources.Strings. in the schema JSON.

    {
    "label": "$Resources.Strings.SaveButton_caption"
    }

    Request binding

    A reference to a request handler, stored as an object that has request and optional params fields.

    {
    "clicked": {
    "request": "crt.SaveRecordRequest",
    "params": {}
    }
    }

    Use optional chaining and default values when reading property values to avoid runtime errors if a property has not been set: const value = propertyValue?.value ?? defaultValue.

  4. Implement the method that writes the updated property values back to the schema when the user changes a field. When you call setPropertyValue, pass one of the following options in the options parameter.

    Example that sets property values of different types
    /* Set a constant value. */
    await this._viewNodeEditor.setPropertyValue('text', { constant: 'Some string' });

    /* Bind to a view model attribute. */
    await this._viewNodeEditor.setPropertyValue('value', { bindToAttribute: 'Account.Name' });

    /* Bind to a localized resource. */
    await this._viewNodeEditor.setPropertyValue('caption', { bindToResource: 'AccountCaption' });

    /* Bind to a request. */
    await this._viewNodeEditor.setPropertyValue('clicked', {
    bindToRequest: {
    request: 'crt.SaveRecordRequest',
    params: { someParam: 'someValue' },
    },
    });

    The bindToRequest option accepts a RequestBindingOptions object with the following properties.

    RequestBindingOptions interface
    interface RequestBindingOptions {
    request: string;
    params?: Record<string, JsonData>;
    }

    setPropertyValue returns a typified object that reflects the value written to the schema. The returned object includes a type field and type-specific fields such as value, attributePath, resourcePath, or requestType, depending on the binding type used.

    To clear a property, set it to a null constant: setPropertyValue(name, { constant: null }).

    To bind a property to a view model attribute, for example, a value that maps to a data source column, use viewModelEditor to manage view model attributes. The table below lists the key methods of viewModelEditor. All methods are asynchronous and return promises. Always use await when calling them.

    Method

    Description

    getAttributeEditor(name)

    Returns an attribute editor, or undefined if the attribute does not exist.

    createAttribute(name, options)

    Creates a new attribute. Throws if the attribute already exists — remove it first using removeAttribute().

    canRemoveAttribute(name)

    Checks whether an attribute can be safely removed.

    removeAttribute(name)

    Deletes an attribute.

    To bind a new attribute to a data source column, use createAttribute with a bindToModel option. Before you bind, verify that the target data source exists using modelEditor.getDataSourceEditor(dataSourceName). The code below shows how to create an attribute with a model binding.

    Example that creates an attribute with a model binding
    const dataSource = await modelEditor.getDataSourceEditor(dataSourceName);
    if (dataSource?.dataSourceType === DataSourceType.EntityDataSource) {
    await viewModelEditor.createAttribute('MyAttribute', {
    bindToModel: { dataSourceName: dataSourceName, dataSourceAttributePath: 'Name' }
    });
    }

4. Add the setup area to the Freedom UI Designer

  1. Create a design-time Angular module.

    1. Go to the "src/app" directory and create the design-time module file.
    2. Add the setup area component to the @CrtModule decorator so that the Freedom UI Designer can display it when a user selects the UI component on the canvas.
    3. Declare the setup area component in the @NgModule decorator and allow custom element schemas.
    Example that creates a design-time Angular module
    /* Register SomeCustomSetupAreaComponent as a view element so that the Freedom UI Designer
    can display it as a setup area when a user selects the UI component on the canvas. */
    @CrtModule({
    viewElements: [SomeCustomSetupAreaComponent],
    })
    /* Declare SomeCustomSetupAreaComponent in the Angular module and allow custom element schemas. */
    @NgModule({
    declarations: [SomeCustomSetupAreaComponent],
    imports: [CommonModule],
    exports: [SomeCustomSetupAreaComponent],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    })
    export class SomeDesignTimeModule { }
  2. Register the setup area component as a custom element so that the browser can render it inside Freedom UI Designer.

    1. Call createCustomElement in the module constructor to convert the setup area component to a custom element.
    2. Define createCustomElement in the browser registry using customElements.define.
    Example that registers the setup area component as a custom element
    constructor() {
    /* Register SomeCustomSetupAreaComponent as a custom element on module initialization. */
    this._registerCustomElement('usr-some-custom-setup-area', SomeCustomSetupAreaComponent);
    }

    private _registerCustomElement(selector: string, component: Type): void {
    if (!customElements.get(selector)) {
    /* Convert the Angular component to a custom element and define it in the browser registry. */
    const elementConstructor = createCustomElement(component, { injector: this._injector });
    customElements.define(selector, elementConstructor);
    }
    }
  3. Import the design-time module into the "app.module.ts" file. To do this, add the design-time module to the imports array of the @NgModule decorator.

    Example that imports the design-time module into the "app.module.ts" file
    @NgModule({
    declarations: [SomeCustomComponent],
    imports: [BrowserModule, SomeDesignTimeModule],
    providers: [],
    })
    export class AppModule implements DoBootstrap { }

5. Link the setup area to the custom UI component

  1. Open the some-ui-component.component.ts file that implements the functionality of the UI component.

  2. Set the propertiesPanel property to the setup area type identifier in the @CrtInterfaceDesignerItem decorator. The value must match the type defined in the @CrtViewElement decorator of the setup area component.

    Example that links the setup area to the UI component
    @CrtInterfaceDesignerItem({
    propertiesPanel: SOME_SETUP_AREA_TYPE_CONSTANT,
    })

    When a user selects the UI component in the Freedom UI Designer, Creatio finds the registered setup area by that identifier and instantiates it.

As a result, the custom setup area will appear in Freedom UI Designer when a user selects the UI component on the canvas. No-code creators will be able to configure the component properties directly in the designer without modifying the Freedom UI page schema manually.


See also

Custom UI component implemented using remote module

Implement a custom setup area for a UI component implemented using remote module