> 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 makes it possible to create 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 it should identify itself with</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 transmitted 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 case of empty values, attributes will not be created.
* If a value update 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 that conforms to 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 they will be recorded in statistics. NOTE! The code should respect the fact that the component has been removed from the DOM - any events sent after the component has been removed may prevent the application from being submitted.
* Apart from the defined attributes, the platform will set the following attributes on the component:
  * **id** - 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>

A fixed 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" %}
If the value @GesTextField1 and type FIELD are provided, the platform will resolve nested components accordingly.
{% endhint %}

A ServiceProxy (ScriptService) can also be attached, which 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) must be provided.
{% endhint %}

## Sample 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.
