> 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" %}
Availability of functionality 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**.

CustomComponent consists of eight elements:

* JavaScript script,
* CSS styles of the component,
* HTML template of the component,
* Input parameter mappings of the component,
* 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 module **Library** and selecting the tab **Custom components** click the button **Add custom component** and in the opened window set the name and location of the created artifact (More information about the editor itself: [Custom component 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> Edit view of the newly created component</em></p></figcaption></figure>

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

Each of the CustomComponents consists of one main function, which is passed a **Scope** of the component:

```
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 methods of the component:

* **afterViewInit** - executed when the component is added to the application's DOM structure,
* **onModelChange** - executed when the model changes (e.g. the value) of the component or the value of input data,
* **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 preserving component state)
  * **componentInput** - map of component input data (keys are defined in section **Inputs** separated by commas)
* methods:
  * getValue() - retrieves the current component value
  * setValue(value) - sets the current component value
  * querySelector(query) - returns the component DOM structure element that matched the selector.
  * putData(key, value) - sets a given value under the key (key) in the component data map - browser client side only
  * saveData(key, value) - sets a given 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 requirements of the ID attribute in HTML) 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 disabled (Availability of the functionality depends on the license and may not be available in all deployments.)
  * setActiveForward() - sets the button navigating to the next page to active (Availability of the functionality depends on the license and may not be available in all deployments.)
  * triggerCustomEvent(eventName) - allows firing a CustomEvent previously defined for a given component
  * sendCurrentValueEvent() - sends an event containing the current value of the CustomComponent together 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 presents 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 CustomComponent</em></p></figcaption></figure>

In line 6, a system function was defined *afterViewInit* initializing buttons *X* and *NEXT,* as well as controlling the visibility of the window. 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 the CustomComponent level 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 obtain *response* call the method *.subscribe()* known from RxJS. As with RxJS, it is also worth calling *unsubscribe()* at the appropriate moment on the returned object. For example *unsubscribe* can be called in the method *onDestroy.*

In case of using ServiceProxy or ScriptService, it should be added 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 section **Input data** the input field IDs of the component 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>

Defined input fields can be fed by other application components in the same way as [composite components (ComplexComponent)](https://docs.eximee.com/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponenty-zlozone#parametry-wejsciowe) - by mapping the relevant data in the section **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 section **Component translations**, which appears after selecting the button in the left panel **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 in the application to which the component has been attached.

Example of adding a translation key:

1. After clicking the button at the bottom of the panel **Add translation** you need to add a translation key and 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 DOM structure of the CustomComponent:

<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 an application or to a composite component in the tab **Translations** the keys from the CustomComponent will appear. We can also add them manually.<br>

<figure><img src="/files/7f0db7449c77538d7a0cf964e108a4254f4979fa" alt=""><figcaption><p><em><strong>Figure 6d.</strong></em> <em>Tab "Translations" 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 enables handling messages via the method **onMessagesUpdate**.

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

## Definition of 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>

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

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

The event itself can be called within the JS script of the customComponent using the method **triggerCustomEvent**, 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.\
For this purpose, click the button located on the right side of the screen **Preview**. Clicking it changes the screen appearance to simulation mode. On the left side we will see windows **JavaScript**, **CSS** and **HTML**, 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 operation without having to embed it on 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 fields it is worth selecting the option **Automatic refresh**. After filling in all fields, click the button **Refresh**. Then the fields with the entered values are hidden, and the component appearance is shown. You can always display the filled-in parameters by clicking the option with the number of parameters and the word **(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 button again **Preview** we will 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/composite component by adding it from the component palette. For this purpose, in the left side panel click the button **Add component** and in the slide-out component panel choose the tab **Custom**, which is available after clicking the symbol ![](/files/d7115ee4c1a584c8686338ae56cdfab37dbd77f6). A list of available CustomComponents in the repository will be displayed.\
At the top of the panel there is a search field allowing quicker finding of the artifact to embed. Adding a 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 section **Input fields** **the component**) by clicking in section **Basic** **properties** the 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

Remember that calling the method **setInactiveForward** within **afterViewInit** will cause the button to be disabled after every change in component visibility - therefore this should be taken into account in the implementation.

Control of the button's activity can depend on the channel in which the application is displayed by means of the conditional statement ***if*** , taking into account session variables **channel** and **channelDescritpion** (remember to map them to the component beforehand).

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

## Calling native API

The $scope object provides the function **callNative**, which takes a function whose parameter is the 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" %}
Availability of functionality 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>

The window object provides methods for controlling the platform loader:

* startSpinner() - enables the loader
* stopSpinner() - disables 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.
