Skip to main content
Version: 8.0

Implement a custom UI component based on a Classic UI page

Level: intermediate
note

The example is relevant to version 8.0.2 and later.

To implement the example:

  1. Set up the page UI. Read more >>>
  2. Set up a custom component. Read more >>>
  3. Add the custom component to the page. Read more >>>
Example

Display the history of the selected account on the Account timeline tab of the custom request page. The tab is a component based on the Timeline Classic UI tab displayed on the Classic UI contact page.

1. Set up the page UI

  1. Create an app based on the Records & business processes template. Instructions: Create an app manually (user documentation).

    For this example, create a Requests app.

  2. Open the form page in the Freedom UI Designer.

    For this example, open Requests form page that includes the Name field out of the box.

  3. Add a field.

    For this example, add the field that contains the account.

    To do this:

    1. Add a field of needed type to the working area of the Freedom UI Designer.

    2. Click and fill out the field properties.

      Element

      Element type

      Property

      Property value

      Field that contains the account

      Dropdown

      Title

      Account

      Code

      UsrAccount

      Lookup

      Account

      Enable adding new values

      Clear the checkbox

  4. Add a tab.

    For this example, add the tab that contains the history of the selected account.

    To do this, click and fill out the tab properties.

    Element

    Property

    Property value

    Tab that contains the history of the selected account

    Title

    Account timeline

  5. Save the changes.

2. Set up a custom component

  1. Open the Configuration section. Instructions: Open the Configuration section.

  2. Select a user-made package to add the schema.

    For this example, select the UsrRequests user-made package.

  3. Create the module schema. To do this, click AddModule.

  4. Fill out the schema properties.

    For this example, use the following schema properties.

    Property

    Property value

    Code

    UsrTimelineModule

    Title

    TimelineModule

  5. Apply the changes.

  6. Implement the business logic of the custom component.

    1. Add the dependencies. To do this, add @creatio-devkit/common library, Base7xViewElement, and ckeditor-base modules as a dependency.

      AMD module dependencies
      /* Declare the AMD module. */
      define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function(sdk, Base7xViewElement) {
      ...
      });
    2. Declare a custom UsrTimelineModule component class.

      UsrTimelineModule
      /* Declare the AMD module. */
      define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function (sdk, Base7xViewElement) {

      /* Declare a "UsrTimelineModule" class. */
      class UsrTimelineModule extends Base7xViewElement {
      set primaryColumnValue(value) {
      this._primaryColumnValue = value;
      this._init();
      }

      get primaryColumnValue() {
      return this._primaryColumnValue;
      }

      set entitySchemaName(value) {
      this._entitySchemaName = value;
      this._init();
      }

      get entitySchemaName() {
      return this._entitySchemaName;
      }

      set cardSchemaName(value) {
      this._cardSchemaName = value;
      this._init();
      }

      get cardSchemaName() {
      return this._entitySchemaName;
      }

      constructor() {
      super("Timeline");
      }

      _init() {
      if (this._primaryColumnValue && this._cardSchemaName && this._entitySchemaName) {
      this.initContext(() => {
      this._moduleId = this.sandbox.id + "_UsrTimelineModule";
      this.sandbox.subscribe("GetColumnsValues", (attributeNames) => this._getColumnValues(attributeNames), null, [this._moduleId]);
      this.sandbox.subscribe("GetEntityInfo", () => this._getEntityInfo(), null, [this._moduleId]);
      this._loadTimelineSchemaModule();
      });
      }
      }

      _loadTimelineSchemaModule() {
      this._moduleId = this.sandbox.loadModule("BaseSchemaModuleV2", {
      id: this._moduleId,
      renderTo: this._renderTo,
      instanceConfig: {
      schemaName: "TimelineSchema",
      isSchemaConfigInitialized: true,
      useHistoryState: false,
      showMask: true,
      parameters: {
      viewModelConfigDiff: {
      "CardSchemaName": this._cardSchemaName,
      "ReferenceSchemaName": this._entitySchemaName,
      "InitialConfig": {
      "entities": []
      }
      },
      },
      }
      });
      }

      _getColumnValues(attributeNames) {
      const values = {};
      attributeNames?.forEach((attributeName) => {
      switch (attributeName) {
      case "Id":
      values[attributeName] = this._primaryColumnValue?.value;
      break;
      case "Name":
      values[attributeName] = this._primaryColumnValue?.displayValue;
      break;
      default: break;
      }
      });
      return values;
      }

      _getEntityInfo() {
      return {
      entitySchemaName: this._entitySchemaName,
      primaryColumnValue: this._primaryColumnValue?.value,
      primaryDisplayColumnValue: this._primaryColumnValue?.displayValue
      };
      }

      getMessages() {
      const messages = super.getMessages();
      return Object.assign(messages, {
      "GetColumnsValues": {
      mode: Terrasoft.MessageMode.PTP,
      direction: Terrasoft.MessageDirectionType.SUBSCRIBE
      },
      "GetEntityInfo": {
      mode: Terrasoft.MessageMode.PTP,
      direction: Terrasoft.MessageDirectionType.SUBSCRIBE
      }
      });
      }

      disconnectedCallback() {
      this.sandbox.unloadModule(this._moduleId, this._renderTo);
      }
      }
      });
    3. Register the UsrTimelineModule module as a component.

      UsrTimelineModule
      /* Declare the AMD module. */
      define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function (sdk, Base7xViewElement) {
      ...,
      /* Register the component. */
      customElements.define('usr-timeline', UsrTimelineModule);
      ...,
      });
    4. Specify that the UsrTimelineModule component is a view element.

      UsrTimelineModule
      /* Declare the AMD module. */
      define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function (sdk, Base7xViewElement) {
      ...,
      /* Register a component as a visual element. */
      sdk.registerViewElement({
      type: 'usr.Timeline',
      selector: 'usr-timeline',
      inputs: {
      primaryColumnValue: {},
      cardSchemaName: {},
      entitySchemaName: {}
      }
      });
      });
  7. Save the changes.

3. Add the custom component to the page

  1. Open the form page in the Freedom UI Designer.

    For this example, open Requests form page.

  2. Open the source code of the Freedom UI page. To do this, click .

  3. Add the dependencies. To do this, add the UsrTimelineModule module of the custom component as a dependency.

    AMD module dependencies
    /* Declare the AMD module. */
    define("UsrRequests_FormPage", /**SCHEMA_DEPS*/["UsrTimelineModule"]/**SCHEMA_DEPS*/, function/**SCHEMA_ARGS*/()/**SCHEMA_ARGS*/ {
    return {
    ...
    }
    });
  4. Add a component.

    1. Go to the viewConfigDiff schema section.
    2. Add the configuration object of the UsrTimelineModule element.
    viewConfigDiff schema section
    viewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
    ...,
    /* Configuration object of the "UsrTimelineModule" element. */
    {
    "operation": "insert",
    "name": "UsrTimelineModule",
    "values": {
    "type": "usr.Timeline",
    "layoutConfig": {
    "column": 1,
    "row": 1,
    "colSpan": 12,
    "rowSpan": 8
    },
    "primaryColumnValue": "$UsrAccount",
    "cardSchemaName": "AccountPageV2",
    "entitySchemaName": "Account"
    },
    "parentName": "GridContainer_0eojs6u",
    "propertyName": "items",
    "index": 0
    },
    ...
    ]/**SCHEMA_VIEW_CONFIG_DIFF*/,
  5. Save the changes.

As a result, Freedom UI Designer will display a stub in place of the custom component.

View the result

To view the outcome of the example:

  1. Open the Requests section.
  2. Create a request that has an arbitrary name. For example, "Request's name."
  3. Select an arbitrary account in the Account field. For example, "Alpha Business."
  4. Open the Account timeline tab.

As a result, Creatio will display the Account timeline tab of the selected account on the request page. View the result >>>

Source code

/* Declare the AMD module. */
define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function(sdk, Base7xViewElement) {

/* Declare a "UsrTimelineModule" class. */
class UsrTimelineModule extends Base7xViewElement {
set primaryColumnValue(value) {
this._primaryColumnValue = value;
this._init();
}

get primaryColumnValue() {
return this._primaryColumnValue;
}

set entitySchemaName(value) {
this._entitySchemaName = value;
this._init();
}

get entitySchemaName() {
return this._entitySchemaName;
}

set cardSchemaName(value) {
this._cardSchemaName = value;
this._init();
}

get cardSchemaName() {
return this._entitySchemaName;
}

constructor() {
super("Timeline");
}

_init() {
if (this._primaryColumnValue && this._cardSchemaName && this._entitySchemaName) {
this.initContext(() => {
this._moduleId = this.sandbox.id + "_UsrTimelineModule";
this.sandbox.subscribe("GetColumnsValues", (attributeNames) => this._getColumnValues(attributeNames), null, [this._moduleId]);
this.sandbox.subscribe("GetEntityInfo", () => this._getEntityInfo(), null, [this._moduleId]);
this._loadTimelineSchemaModule();
});
}
}

_loadTimelineSchemaModule() {
this._moduleId = this.sandbox.loadModule("BaseSchemaModuleV2", {
id: this._moduleId,
renderTo: this._renderTo,
instanceConfig: {
schemaName: "TimelineSchema",
isSchemaConfigInitialized: true,
useHistoryState: false,
showMask: true,
parameters: {
viewModelConfigDiff: {
"CardSchemaName": this._cardSchemaName,
"ReferenceSchemaName": this._entitySchemaName,
"InitialConfig": {
"entities": []
}
},
},
}
});
}

_getColumnValues(attributeNames) {
const values = {};
attributeNames?.forEach((attributeName) => {
switch (attributeName) {
case "Id":
values[attributeName] = this._primaryColumnValue?.value;
break;
case "Name":
values[attributeName] = this._primaryColumnValue?.displayValue;
break;
default: break;
}
});
return values;
}

_getEntityInfo() {
return {
entitySchemaName: this._entitySchemaName,
primaryColumnValue: this._primaryColumnValue?.value,
primaryDisplayColumnValue: this._primaryColumnValue?.displayValue
};
}

getMessages() {
const messages = super.getMessages();
return Object.assign(messages, {
"GetColumnsValues": {
mode: Terrasoft.MessageMode.PTP,
direction: Terrasoft.MessageDirectionType.SUBSCRIBE
},
"GetEntityInfo": {
mode: Terrasoft.MessageMode.PTP,
direction: Terrasoft.MessageDirectionType.SUBSCRIBE
}
});
}

disconnectedCallback() {
this.sandbox.unloadModule(this._moduleId, this._renderTo);
}
}

/* Register the component. */
customElements.define('usr-timeline', UsrTimelineModule);

/* Register a component as a visual element. */
sdk.registerViewElement({
type: 'usr.Timeline',
selector: 'usr-timeline',
inputs: {
primaryColumnValue: {},
cardSchemaName: {},
entitySchemaName: {}
}
});

return Terrasoft.UsrTimelineModule;
});

Resources

Package with example implementation