# External WebComponent

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

ExternalWebComponent is a specialized component that enables creating controls outside the set available on the palette. It is enough to write your own WebComponent using HTML and JavaScript, and 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 should identify itself</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 in the application |
| 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 a new value is received from the server, the attribute value will be changed.
* For 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 may 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 the event **change** with the field **details** containing an object that satisfies 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 may emit the 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 is removed from the DOM - any events sent after the component is removed may prevent the application from being submitted.
* In addition to 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>

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

You can also connect a ServiceProxy (ScriptService), 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 %}

## 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: 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:

```
GET https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/external-webcomponent.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
