> 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/external-webcomponent.md).

# External WebComponent

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

ExternalWebComponent is a specialized component that enables the creation of controls outside the set available on the palette. It is enough to write your own WebComponent using HTML and JavaScript, and then return the path to a file with such content via a service (ScriptService or ServiceProxy).

## Component input parameters

<table><thead><tr><th width="213.199951171875">Parameter</th><th>Description</th></tr></thead><tbody><tr><td>componentUrl</td><td>full link to the WebComponent source</td></tr><tr><td>tag</td><td>the tag by which it is to be identified</td></tr><tr><td>inputs</td><td>list of input parameters for the Component as JSON</td></tr></tbody></table>

## List of input model parameters for the WebComponent <a href="#externalwebcomponent-listaparametrowmodeluwejsciowegodowebcomponentu" id="externalwebcomponent-listaparametrowmodeluwejsciowegodowebcomponentu"></a>

| Input parameter | Possible value       | Description                                        |
| --------------- | -------------------- | -------------------------------------------------- |
| name            | \*                   | Parameter name                                     |
| value           | \*                   | Constant value or component name on the form       |
| type            | CONSTANT / FIELD     | Type of the passed value                           |
| deliveryType    | ATTRIBUTE / PROPERTY | Method of delivering the value to the WebComponent |

## Communication <a href="#externalwebcomponent-komunikacja" id="externalwebcomponent-komunikacja"></a>

* Any parameters for the component (defined in Eximee Designer) are passed to the component via attributes. If we receive a new value from the server, the attribute value will be changed.
* In the case of empty values, attributes will not be created.
* If an update to the value clears the value of a given attribute, the platform will remove that attribute from the element.
* The component can use any methods exposed by the Eximee API in the Window object

  ```javascript
  export interface ExWebformsWindow extends Window {
      getComponentValue: (componentId: string) => unknown;
      setComponentValue: (sourceComponentId: string, componentId: string, newValue: string) => unknown;
      updateExternalSectionValue: (externalSectionId: string, newValue: string) => unknown;
      finishApplication: () => void;
      applicationSetTitle: () => void;
      goForward: () => void;
      goBackward: () => void;
      returnToOriginalForm: () => boolean;
  }
  ```
* The component can change its own value by emitting an event **change** with the field **details** containing an object satisfying the interface `{ value: string }`. This can be achieved, for example, by creating an object of type `CustomEvent` (e.g.: `new CustomEvent('change', {detail: {value: event.target.value}})`). Additionally, the component can emit events **focus** and **blur** - they will not affect the application logic, but will be recorded in statistics. NOTE! The code should respect the fact that the component was removed from the DOM - any events sent after removing the component may prevent the application from being submitted.
* Apart from the defined attributes, the platform will set the following attributes on the component:
  * **id** - the element identifier in the DOM structure. The platform ensures its uniqueness and compliance with the HTML specification
  * **component-id** - component identifier - this identifier should be used when communicating with the platform
  * **value** - current value of the component
  * **translations** - JSON with translations (key-value) for literals in the WebComponent
* The attribute may be set by the platform after connectedCallback - you need to hook into attributeChangedCallback

## Configuration <a href="#externalwebcomponent-konfiguracja" id="externalwebcomponent-konfiguracja"></a>

Static configuration may look as follows:

```xml
<p1:GesExternalWebComponent id="GesExternalWebComponent2" mid="GesExternalWebComponent2" inheritLayout="false" tag="img-only" componentUrl="https://dev.bank.eximee.consdata.local/bank-demo-ewc/imgonly.js">
  <data:ListeningOn/>
  <data:ClearOn/>
  <p1:GesExternalWebComponent.layoutData>
    <ns6:GridData horizontalAlignment="FILL" horizontalSpan="17" verticalAlignment="CENTER"/>
  </p1:GesExternalWebComponent.layoutData>
  <data:ExternalWebComponentInputMapping>
    <data:ExternalWebComponentMapping value="some-value" name="name1" type="CONSTANT" deliveryType="ATTRIBUTE"/>
    <data:ExternalWebComponentMapping value="GesTextField1" name="name2" type="FIELD" deliveryType="PROPERTY"/>
  </data:ExternalWebComponentInputMapping>
</p1:GesExternalWebComponent>
```

{% hint style="warning" %}
In the case of providing the value @GesTextField1 and type FIELD, the platform will appropriately resolve nested components.
{% endhint %}

You can also attach a ServiceProxy (ScriptService) that will return the above data.

```xml
<p1:GesExternalWebComponent id="GesExternalWebComponent1" mid="GesExternalWebComponent1" inheritLayout="false">
  <data:ExternalDataSource name="demo_cross_sell_ewc" type="SCRIPT_SERVICE" changesWidgetAttributes="false" version="*">
    <data:OutputFields>
      <data:Field localName="componentUrl" serviceName="url_to_webcomponent"/>
      <data:Field localName="tag" serviceName="webcomponent_tag"/>
    </data:OutputFields>
  </data:ExternalDataSource>
  <data:ListeningOn/>
  <data:ClearOn/>
  <p1:GesExternalWebComponent.layoutData>
    <ns6:GridData horizontalAlignment="FILL" horizontalSpan="17" verticalAlignment="CENTER"/>
  </p1:GesExternalWebComponent.layoutData>
</p1:GesExternalWebComponent>
```

{% hint style="warning" %}
Attaching an EDS (external data source) to the ExternalWebComponent will overwrite all original values.

This means that all input parameters (url, tag, inputs) need to be provided.
{% endhint %}

## Example WebComponent <a href="#externalwebcomponent-przykladowywebcomponent" id="externalwebcomponent-przykladowywebcomponent"></a>

{% code expandable="true" %}

```javascript
const imgTemplate = document.createElement('template');
imgTemplate.innerHTML = `
    <div class="wrapper">
        <img id="noAttributeAndProperty" src="https://prowly-uploads.s3.eu-west-1.amazonaws.com/uploads/4843/assets/191020/large-09ba51481c9c5dd157eea3438af2bcbf.png" width="300" height="350"/>
        <img id="falseAtribute" style="display: none" src="https://upload.wikimedia.org/wikipedia/en/1/14/WO%C5%9AP.svg" width="300" height="350"/>
        <img id="trueAtribute" style="display: none" src="https://www.wroclaw.pl/go/download/img-32cf4a052df7bd08570783a8351863eb/wosp-26-jpg.jpg" width="300" height="350"/>
        <img id="falseProperty" style="display: none" src="https://static.wosp.org.pl/trunk/uploaded/sended/files/programy/logo-rur-pl.png?1573732254027" width="300" height="350"/>
        <img id="trueProperty" style="display: none" src="https://admonkey.pl/wp-content/uploads/2017/01/logo_wosp.jpg" width="300" height="350"/>
    </div>`;
 
 
class ImgOnly extends HTMLElement {
 
    constructor() {
        super();
        this.shadow = this.attachShadow({
            mode: 'open'
        });
    }
 
    getAtributesAndProperties() {
        let atrGroup = null
        let propsGroup = null
        let element = document.getElementById('GesComplexComponent1_GesExternalWebComponent2-element')
        if (!!element) {
            atrGroup = element.getAttribute("atrgroup")
            propsGroup = element['propsGroup']
        }
        if ((atrGroup == null || atrGroup == undefined) && (propsGroup == null || propsGroup == undefined)) {
            this.shadow.getElementById("noAttributeAndProperty").style.display = "inline-block";
            return;
        } else {
            element.shadowRoot.getElementById("noAttributeAndProperty").style.display = "none";
        }
        if (atrGroup === "true") {
            element.shadowRoot.getElementById("trueAtribute").style.display = "inline-block";
            element.shadowRoot.getElementById("falseAtribute").style.display = "none";
        }
        if (atrGroup === "false") {
            element.shadowRoot.getElementById("falseAtribute").style.display = "inline-block";
            element.shadowRoot.getElementById("trueAtribute").style.display = "none";
        }
        if (propsGroup === "true") {
            element.shadowRoot.getElementById("trueProperty").style.display = "inline-block";
            element.shadowRoot.getElementById("falseProperty").style.display = "none";
        }
        if (propsGroup === "false") {
            element.shadowRoot.getElementById("falseProperty").style.display = "inline-block";
            element.shadowRoot.getElementById("trueProperty").style.display = "none";
        }
 
    }
 
    connectedCallback() {
        this.shadow.appendChild(imgTemplate.content.cloneNode(true));
        setInterval(this.getAtributesAndProperties, 500);
 
    }
 
    attributeChangedCallback(name, oldValue, newValue) {
        switch (name) {
            case 'atrgroup':
                this.getAtributesAndProperties();
                break;
        }
    }
 
 
    static get observedAttributes() {
        return ['atrgroup'];
    }
}
 
window.customElements.define('img-only', ImgOnly);
```

{% endcode %}


---

# 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/external-webcomponent.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.
