> For the complete documentation index, see [llms.txt](https://docs.eximee.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponent-niestandardowy-customcomponent.md).

# Custom component - CustomComponent

{% hint style="warning" %}
Feature availability depends on the license and may not be available in all deployments.
{% endhint %}

The custom component (CustomComponent) allows you to create your own components for the application using the language **JavaScript**.

A CustomComponent consists of eight elements:

* JavaScript script,
* Component CSS styles,
* Component HTML template,
* Component input parameter mappings,
* List of used services,
* List of actions available for this component,
* Translations of texts for the component,
* Preview.

## Creating a component <a href="#komponentniestandardowycustomcomponent-tworzeniekomponentu" id="komponentniestandardowycustomcomponent-tworzeniekomponentu"></a>

A new component is created in the same way as other components. After going to the **Library** module and selecting the **Custom components** tab, click the **Add custom component** button and in the opened window set the name and location of the artifact being created (More information about the editor itself: [Custom components editor](/documentation/documentation-en/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponent-niestandardowy-customcomponent/edytor-komponentow-niestandardowych.md))

<figure><img src="/files/29b2bd0e2de3c01d2b3d4db8d21baf1e4cae2329" alt=""><figcaption><p><em><strong>Figure 1.</strong> Editing view of the newly created component</em></p></figcaption></figure>

## JavaScript script <a href="#komponentniestandardowycustomcomponent-skryptjavascript" id="komponentniestandardowycustomcomponent-skryptjavascript"></a>

Each CustomComponent consists of one main function, to which the **Scope** of the component is passed:

```
function($scope) {
  
}
```

Using the scope, the creator can, among other things, retrieve component data, input data, and react to certain events from the component lifecycle. The user can implement three system component methods:

* **afterViewInit** - executed when the component is added to the application's DOM structure,
* **onModelChange** - executed when the model (e.g. value) of the component or the input data value changes,
* **onDestroy** - executed when the component is removed from the application's DOM structure.

Additionally, the component scope provides several useful elements:

* fields:
  * **domId** - component ID in the application's DOM structure
  * **componentId** - component ID
  * **componentMid** - component MID
  * **visible** - variable controlling component visibility
  * **translations** - translation map defined at the component creation stage
  * **componentId** - map of component input parameters
  * **componentData** - map of internal component data (allows the component state to be preserved)
  * **componentInput** - map of component input data (keys are defined in the **Inputs** section, separated by commas)
* methods:
  * getValue() - retrieves the current value of the component
  * setValue(value) - sets the current value of the component
  * querySelector(query) - returns the DOM element of the component that matched the selector.
  * putData(key, value) - sets the specified value (value) under the key (key) in the component data map - browser client side only
  * saveData(key, value) - sets the specified value (value) under the key (key) in the component data map - also on the server side
  * getData(key) - retrieves the value specified under the key (key) in the component data map
  * translate(key) - returns a translation from the translation map
  * clean() - clears the scope object when it is no longer used by the CustomComponent
  * callServiceProxy(serviceName, params) - allows calling ServiceProxy and ScriptService services synchronously
  * callServiceProxyAsync(serviceName, params) - allows calling ServiceProxy and ScriptService services asynchronously
  * initTooltip(id, element, data) - allows initializing a tooltip with the given identifier (required value, must meet all HTML ID attribute requirements) on the passed element
  * showTooltip(id) - shows the tooltip with the given id
  * hideTooltip(id) - hides the tooltip with the given id
  * destroyTooltip(id) - destroys the tooltip with the given id
  * destroyAllTooltips() - destroys all tooltips of the given component
  * goForward() - navigates to the next (allowed) page or submits the application (when the user is on the last page of the application)
  * goBackward() - navigates to the previous (allowed) page
  * setInactiveForward() - sets the button navigating to the next page to inactive (Feature availability depends on the license and may not be available in all deployments.)
  * setActiveForward() - sets the button navigating to the next page to active (Feature availability depends on the license and may not be available in all deployments.)
  * triggerCustomEvent(eventName) - allows triggering a CustomEvent previously defined for a given component
  * sendCurrentValueEvent() - sends an event containing the current value of the CustomComponent along with its id
  * isPageValid() - returns information whether there are validation errors on the page

## Component interfaces

{% code expandable="true" %}

```tsx
interface ExCustomComponentScope {
    // Methods that can be provided
    onDestroy?: () => void;
    afterViewInit?: () => void;
    onModelChange?: () => void;
    onMessagesUpdate?: (messages: ExWidgetMessage[]) => void;
 
    // Fields provided by the platform
    domId: string;
    componentId: string;
    componentMid: string;
    translations: { [key: string]: string; };
    componentInput: { [key: string]: string[]; };
    componentData: { [key: string]: string; };
    serviceResponses: { [key: string]: { [key: string]: string }[] };
    visible: boolean;
 
    // Methods provided by the platform - do not override them
    callNative(nativeFunction: (api: NativeAppApi) => any): void
    getValue(): string;
    setValue(value: string): void;
    /**
     * @deprecated New CustomComponents should use querySelector
    */
    queryChild(query: string): JQuery;
    querySelector(query: string): Element;
    putData(key: string, value: string): void;
    saveData(key: string, value: string): void;
    getData(key: string): string;
    translate(key: string): string;
    schedule(func: () => any): void;
    clean(): void;
    callServiceProxy(serviceName: string, params: { [key: string]: string[] }): Observable<ExServiceProxyResponse>;
    callServiceProxyAsync(serviceName: string, params: { [key: string]: string[] }): Observable<ExServiceProxyResponse>;
    initTooltip(id: string, element: any, data: ExWidgetTooltip): void;
    destroyTooltip(id: string): void;
    showTooltip(id: string): void;
    hideTooltip(id: string): void;
    destroyAllTooltips(): void;
    goForward(): void;
    goBackward(): void;
    setActiveForward(): void;
    setInactiveForward(): void;
    triggerCustomEvent(event: string): void;
    sendCurrentValueEvent(): void;
    isPageValid(): Observable<boolean>;
}
 
interface ExServiceProxyResponse {
    name: string;
    componentId: string;
    response: { [key: string]: string }[];
}
 
interface ExWidgetTooltip {
    text: string;
    position: ExWidgetTooltipPosition;
    type: ExWidgetTooltipType;
    width?: number;
    height?: number;
    styleClasses?: string;
    onFocus?: boolean;
}
 
enum ExWidgetTooltipPosition {
    TOP,
    BOTTOM,
    LEFT,
    RIGHT,
    ADAPTIVE,
// Deprecated:
    LEFT_TOP,
    LEFT_BOTTOM,
    RIGHT_TOP,
    RIGHT_BOTTOM
}
 
enum ExWidgetTooltipType {
    HOVER,
    BUTTON
}
interface ExWidgetMessage {
    getMessage(): string;
    getType(): ExWidgetMessageType;
}
 
enum ExWidgetMessageType {
    VALIDATION_POPUP,
    VALIDATION,
    INFO,
    COMPONENT_INFO
}
```

{% endcode %}

## Example component function

{% code lineNumbers="true" %}

```javascript
function($scope) {
      $scope.closePopup = function() {
        $scope.queryChild('.kg-positive-decision-popup-wrapper').fadeOut(200);
        $scope.saveData('visible', 'false');
      };
      $scope.afterViewInit = function() {
        let visible = $scope.getData('visible');
        if(visible === 'false') {
          $scope.queryChild('.kg-positive-decision-popup-wrapper').hide();
        } else {
          $scope.closeButton = $scope.queryChild('.kg-positive-decision-popup-close-button');
          $scope.closeButton.on('click', $scope.closePopup);
          $scope.nextButton = $scope.queryChild('.kg-positive-decision-popup-next-button');
          $scope.nextButton.on('click', $scope.closePopup)
        }
      };
    }
```

{% endcode %}

In the above example, a component was defined that displays a Popup on the application with information about a positive credit decision:

<figure><img src="/files/91281cd1086ca0ef5730c9f2a100ea06902b34ad" alt=""><figcaption><p><em><strong>Figure 2.</strong></em> <em>Popup designed using a CustomComponent</em></p></figcaption></figure>

In line 6, the system function was defined *afterViewInit* initializing the buttons *X* and *NEXT,* as well as controlling the window visibility. In line 2, a function executed when one of the two buttons is clicked was defined.

Popup DOM structure:

{% code lineNumbers="true" %}

```html
<div class='kg-positive-decision-popup-wrapper'>
  <div class='kg-positive-decision-popup'>
    <div class='kg-positive-decision-popup-title-wrapper'>
        <div class='kg-positive-decision-popup-title'>
            _{kg.positive.decision.popup.title}
        </div>
        <button class='kg-positive-decision-popup-close-button'></button>
        <div class='clear'></div>
    </div>
    <div class='kg-positive-decision-popup-content-wrapper'>
        <div class='kg-positive-decision-popup-content-first-paragraph'>
            _{kg.positive.decision.popup.content.first.paragraph}
        </div>
        <div class='kg-positive-decision-popup-content-second-paragraph'>
            _{kg.positive.decision.popup.content.second.paragraph}
        </div>
    </div>
    <div class='kg-positive-decision-popup-next-button-wrapper'>
        <button class='kg-positive-decision-popup-next-button'>_{kg.positive.decision.popup.next.button}</button>
        <div class='clear'></div>
    </div>
  </div>
</div>
```

{% endcode %}

In the component template definition, you can refer to defined translations using the convention **\_{TRANSLATION\_KEY}** - example in line 5.

### **Calling scripts or ServiceProxy**

From a CustomComponent, you can call ServiceProxy and ScriptService services using the methods *callServiceProxy* and *callServiceProxyAsync.* Both methods return *Observable* with response in the following format:

```
{
    name: string;
    componentId: string;
    response: { [key: string]: string }[];
}
```

To get the *response* you need to call the *.subscribe()* method known from RxJS. As in RxJS, it is also worth calling *unsubscribe()* at the appropriate time on the returned object. For example, *unsubscribe* can be called in the *onDestroy.*

When using ServiceProxy or ScriptService, you need to add it to the list of used services on the CustomComponent:

<figure><img src="/files/4367df57c85b1b53c45e950f77dee1d8648c9c09" alt=""><figcaption><p><em><strong>Figure 3.</strong></em> <em>Section "Used services"</em></p></figcaption></figure>

## Component input fields <a href="#komponentniestandardowycustomcomponent-polawejsciowekomponentu" id="komponentniestandardowycustomcomponent-polawejsciowekomponentu"></a>

In the **Input data** section, the IDs of the component input fields are defined. IDs should not contain spaces.

<figure><img src="/files/a9a0213b78eea98dba1457337bd52dda90c85702" alt=""><figcaption><p><em><strong>Figure 4.</strong></em> <em>Section "Input data"</em></p></figcaption></figure>

The defined input fields can be fed by other application components in the same way as [complex components (ComplexComponent)](https://docs.eximee.com/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponenty-zlozone#parametry-wejsciowe) - by mapping the appropriate data in the **INPUT PARAMETERS**:

<figure><img src="/files/8ec2fc7f5e109b084e683d55c42151a86bad08eb" alt=""><figcaption><p><em><strong>Figure 5.</strong> Example of the "Input parameters" section for a CustomComponent added to the application</em></p></figcaption></figure>

## Translations

Dedicated internationalized texts are defined in the **Component translations**section, which appears after selecting the **Translations**.

<figure><img src="/files/0078d408b1fcc19ff852d9b2d773c21fe609ddab" alt=""><figcaption><p><em><strong>Figure 6a.</strong></em> <em>Section "Component translations"</em></p></figcaption></figure>

In this view, the key and default value of the text handled in the CustomComponent are defined. Text translations in the required languages are defined in the standard way on the application to which the component has been attached.

Example of adding a translation key:

1. After clicking the **Add translation** button at the bottom of the panel, add a translation key and a default value:

   <figure><img src="/files/e6ad8bddd9acb7aee85fa7c0a7fde4b499e219b7" alt=""><figcaption><p><em><strong>Figure 6b.</strong></em> <em>Adding a new key and translation</em></p></figcaption></figure>
2. The added translation key can be used in the CustomComponent DOM structure:

<figure><img src="/files/9435580306228ac6b3c2ba23c3133f3d639b8da1" alt=""><figcaption><p><em><strong>Figure 6c.</strong></em> <em>Section "DOM" with the example key "kg-final-survey-popup-title" entered</em></p></figcaption></figure>

3. After adding the CustomComponent to the application or to a complex component in the **Translations** tab, the keys from the CustomComponent will appear. They can also be added manually.<br>

<figure><img src="/files/7f0db7449c77538d7a0cf964e108a4254f4979fa" alt=""><figcaption><p><em><strong>Figure 6d.</strong></em> <em>"Translations" tab with CustomComponent keys</em></p></figcaption></figure>

## Handling messages

To make the CustomComponent handle validation messages itself, select the option in the parameters section **Custom error message display**. This option allows message handling via the method **onMessagesUpdate**.

<figure><img src="/files/4e0782a30b39f44f4dab3760cf47bfded671f3f2" alt=""><figcaption><p><em><strong>Figure 7.</strong> Enabled "Custom error message display" option</em></p></figcaption></figure>

## Defining custom events for the component

For each CustomComponent, individual actions can be defined (**CustomEvents**). They are attached and handled in the same way as standard events defined in the platform. The action definition looks as follows:

<figure><img src="/files/350b5016f2e647a99ffc63517f1e4eaa54a5cc40" alt=""><figcaption><p><em><strong>Figure 8.</strong> Actions added for the component</em></p></figcaption></figure>

Actions defined in this way can be attached on the application to a given action. For example, the TEST\_EVENT\_A action is used to open the popup:

<figure><img src="/files/9e76a56c48662fd6c13978ac2181308bc21f06dd" alt=""><figcaption><p><em><strong>Figure 9.</strong> Application properties view - "Actions" section with the action defined from the CustomComponent</em></p></figcaption></figure>

The event itself can be invoked inside the CustomComponent's JS script using the **triggerCustomEvent**method, for example:

```javascript
$scope.triggerCustomEvent('TEST_EVENT_A');
```

## Component simulation <a href="#komponentniestandardowycustomcomponent-symulacjakomponentu" id="komponentniestandardowycustomcomponent-symulacjakomponentu"></a>

To check the operation of the created CustomComponent, you can use the simulation function.\
To do this, click the **Preview**button located on the right side of the screen. Clicking it changes the screen to simulation mode. On the left side you will see the **JavaScript**, **CSS** and **HTML**windows, and on the right the component parameters (provided that input parameters have been defined). After starting the preview, we can feed the component with variables retrieved in the component and observe its behavior without having to embed it in the application and run it in the development environment.

<figure><img src="/files/79096dfab25365cadddc74b5c183dd2bea62e1b2" alt=""><figcaption><p><em><strong>Figure 10.</strong> Component view with preview enabled, without filling in input parameters</em></p></figcaption></figure>

If we want changes in the preview to be shown live, before filling in the component parameter field values it is worth selecting the option **Automatic refresh**. After filling in all fields, click the **Refresh**button. The fields with entered values will then hide, and the component view will appear. You can always show the filled-in parameters by clicking the option with the number of parameters and the label **(show)**.

<figure><img src="/files/500814d3f34101427073e9752497387671df70b7" alt=""><figcaption><p><em><strong>Figure 11.</strong> Component view with simulation</em></p></figcaption></figure>

After clicking the **Preview** button again, we return to the standard component view with the list of parameters on the left side.

## Embedding in the application

The created CustomComponent is embedded in the application/in a complex component by adding it from the component palette. To do this, click the **Add component** button in the left sidebar and in the slid-out component panel select the **Custom**tab, which is available after clicking the symbol ![](/files/d7115ee4c1a584c8686338ae56cdfab37dbd77f6). A list of CustomComponents available in the repository will be displayed.\
At the top of the panel there is a search field that makes it easier to find the artifact to embed. Adding the component consists of dragging it from the palette and dropping it in the appropriate place on the application.

<figure><img src="/files/f7b205aa00bcc7a256ade5b6c84656404bcbcf03" alt=""><figcaption><p><em><strong>Figure 12.</strong></em> <em>List of components after clicking the Custom tab</em></p></figcaption></figure>

\
After embedding the component in the application, you need to feed the component input fields (defined according to the **Input fields** **of the component**section) by clicking in the **Basic** **properties** option **INPUT PARAMETERS**:

<figure><img src="/files/b40c3535ba7762e0bdd7ef4bf947207f20b8db85" alt=""><figcaption><p><em><strong>Figure 13.</strong></em> <em>Window for defining CustomComponent input parameters</em></p></figcaption></figure>

## Controlling the activity of the button navigating to the next page

In the JavaScript tab of the edited CustomComponent, we can use the methods:

* **setInactiveForward()** - sets the button navigating to the next page to disabled
* **setActiveForward**() - sets the button navigating to the next page to active

It should be remembered that calling the method **setInactiveForward** inside **afterViewInit** will disable the button after every change in component visibility - therefore this should be taken into account in the implementation.

The button's activity can be made dependent on the channel in which the request is displayed using a conditional statement ***if*** , taking session variables into account **channel** and **channelDescription** (remember to map them to the component beforehand).

{% hint style="warning" %}
Feature availability depends on the license and may not be available in all deployments.
{% endhint %}

## Calling the native API

The $scope object provides the function **callNative**, which takes a function whose parameter is a native API object (signature: callNative(nativeFunction: (api: NativeAppApi) => any): void). The api object has a defined interface provided by the eximee platform. The function requested on the native object will be called only if this object is available in the context.

```
function($scope) {
    $scope.afterViewInit = function() {
        $scope.callNative(nativeApi => nativeApi.setTitle('title'));
    }
}
```

{% hint style="info" %}
Feature availability depends on the license and may not be available in all deployments.
{% endhint %}

## Controlling the platform loader <a href="#komponentniestandardowycustomcomponent-sterowanieloaderemplatformowym" id="komponentniestandardowycustomcomponent-sterowanieloaderemplatformowym"></a>

On the window object, methods are available that allow controlling the platform loader:

* startSpinner() - turns on the loader
* stopSpinner() - turns off the loader


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponent-niestandardowy-customcomponent.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
