# Komponent specjalizowany - ExternalSection

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

## Właściwości komponentu

| Właściwość Eximee Designer | Nazwa atrybutu w Źródle | Opis                                                                                   |
| -------------------------- | ----------------------- | -------------------------------------------------------------------------------------- |
| **Adresu URL zasobu**      | url                     | Umożliwia podanie adresu URL zasobu do osadzenia wewnątrz komponentu specjalizowanego. |

## Zewnętrzne źródło danych dla komponentu specjalizowanego

Zawartość komponentu specjalizowanego, poza podaniem URL do zasobu, może być dostarczana za pomocą zewnętrznego źródła danych typu **SECTION**. Procedura konfiguracji źródła danych jest opisana w rozdziale [Przykład podpięcia w komponencie usługi](/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/zasilanie-wartosciami-z-zewnetrznych-zrodel/przyklad-podpiecia-w-komponencie-uslugi.md).

## ExternalSection w kanale GWT

Dla wszystkich *ExternalSection* tworzących DOM i wykorzystujących dawne klasy GWT należy:

* dla właściwego ostylowania:
  * nadać na tych elementach w Eximee Designerze klasę (**styleName**): **legacy** (np. w **ExternalSection** rysowany jest przycisk, znajduje się slider ostylowany po staremu)
  * lub dorzucić w samej **ExternalSection** na root elemencie klasę: **legacy** (przezroczysta dla starych formsów)
* nadać na elemencie w Eximee Designerze klasę: *external-section-content* (**ExternalSection** bez klasy *external-section-content* nie będą zajmowały miejsca na wniosku. Nie będą również powodowały dodania małego *spacera* rozdzielającego komponenty.)

W **legacy** nie wszystkie style są wspierane.

Z **legacy** będzie spójny z nowymi formsami (klasa potrafiąca ostylować część struktury wniosku).

Można dla starych ES oprócz dwóch wymienionych powyżej klas nadawać także nowe. Dla nowych można skorzystać z powyższych lub nadać nowe.

<figure><img src="/files/HU9jtTe82PVFzUI7f8D5" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Przykładowy wygląd komponentu w Eximee Designerze</em></p></figcaption></figure>

Jeśli są wstawiane komponenty od teraz (bez użycia starych klas), można nadać dowolną (nową) klasę, jeśli korzysta się ze starych to trzeba dodać *legacy.*

## Tworzenie usługi zwracającej treść ExternalSection w Java

### Nowe ServiceProxy API (od wersji 0.63.0)

Parametry wejściowe:

* Wejściem jest obiekt typu **ExternalSectionInput** zawierający następujące pola:
  * **params** (dostęp przez metodę **getParams**()) - mapa parametrów zmapowanych do usługi na szablonie wniosku
  * **targetApplication** (dostęp przez metodę **getTargetApplication**()) - identyfikator kanału wywołującego usługę. Aktualne kanały:
    * "W4" - aplikacja webforms (stare webformsy GWT)
    * "ex-forms" - aplikacja ex-webforms (nowa aplikacja angularowa)
* Dodatkowo, w mapie parametrów zawsze przekazywany jest parametr "**componentId**" wskazujący identyfikator komponentu, na którym osadzona jest usługa

Parametry wyjściowe:

* Wyjściem jest obiekt **ExternalSectionOutput** zawierający następujące pola:
  * **output** (przekazywany również w jednoparametrowym konstruktorze) - wyjście usługi w języku HTML (w kodowaniu UTF-8)

```java
package pl.consdata.eximee.examples;
  
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
  
import pl.consdata.iew.serviceproxy.api.exceptions.ServiceProxyException;
import pl.consdata.iew.serviceproxy.api.section.AbstractExternalSection;
import pl.consdata.iew.serviceproxy.api.section.ExternalSectionInput;
import pl.consdata.iew.serviceproxy.api.section.ExternalSectionOutput;
import pl.consdata.iew.serviceproxy.api.types.ServiceProxyField;
  
@Component
@Service(AbstractExternalSection.class)
public class NewApiExampleExternalSection extends AbstractExternalSection {
  
   public NewApiExampleExternalSection() {
      this.name = "NewApiExampleExternalSection";
      this.inputFields.add(new ServiceProxyField(ENTRY_PARAM));
   }
  
   @Override
   public ExternalSectionOutput callServiceForExternalSection(ExternalSectionInput externalSectionInput)
         throws ServiceProxyException {
      String param = getSingleValue(externalSectionInput.getParams(), ENTRY_PARAM, "wartość domyślna");
      if ("W4".equals(externalSectionInput.getTargetApplication())) {
         return new ExternalSectionOutput(String.format("<b>Webforms GWT</b><br><b>Parametr wejściowy:</b>%s<br>",
               param));
      } else if ("ex-forms".equals(externalSectionInput.getTargetApplication())) {
         return new ExternalSectionOutput(String.format("<b>EX-webforms</b><br><b>Parametr wejściowy:</b>%s<br>",
               param));
      } else {
         return new ExternalSectionOutput(String.format("<b>Kanał: %s</b><br><b>Parametr wejściowy:</b>%s<br>",
               externalSectionInput.getTargetApplication(),
               param));
      }
   }
  
   static final String ENTRY_PARAM = "parametrWejsciowy";
}
```

### Stare ServiceProxy API (od wersji 0.63.0 oznaczone jako deprecated)

Parametry wejściowe:

* **targetApplication** (dostęp przez metodę **getTargetApplication**()) - identyfikator kanału wywołującego usługę. Aktualne kanały:
  * W4 - aplikacja webforms (stare webformsy GWT)
  * OTHER (od wersji 0.63.0 API) - każdy kanał inny niż W4
* **params** - mapa parametrów zmapowanych do usługi na szablonie wniosku
* dodatkowo, w mapie parametrów zawsze przekazywany jest parametr "**componentId**" wskazujący identyfikator komponentu, na którym osadzona jest usługa

Parametry wyjściowe:

* Wyjściem jest obiekt typu String, w którym znajduje się wyjście usługi w języku HTML (w kodowaniu UTF-8)

```java
package pl.consdata.eximee.account.szkolenie;
  
import static org.apache.commons.lang3.StringUtils.EMPTY;
  
import java.util.List;
import java.util.Map;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
  
import pl.consdata.iew.serviceproxy.api.exceptions.ServiceProxyException;
import pl.consdata.iew.serviceproxy.api.section.AbstractExternalSectionServiceProxy;
import pl.consdata.iew.serviceproxy.api.section.ExternalSectionTargetApplication;
import pl.consdata.iew.serviceproxy.api.types.ServiceProxyField;
  
@Component
@Service(AbstractExternalSectionServiceProxy.class)
public class ExampleExternalSection extends AbstractExternalSectionServiceProxy {
  
    public ExampleExternalSection() {
        this.name = "ExampleExternalSection";
        this.description = "ExampleExternalSection description";
        this.inputFields.add(new ServiceProxyField(INPUT_FIELD));
    }
  
    @Override
    public String callServiceForExternalSection(
            ExternalSectionTargetApplication targetApplication,
            Map<String, List<String>> params) throws ServiceProxyException {
        String input = getSingleValue(params, INPUT_FIELD, EMPTY);
        return String.format("<script>alert('%s')</script>", input);
    }
  
    private static final String INPUT_FIELD = "input";
  
}
```

### Projektowanie komponentów specjalizowanych

Usługa zasilająca komponent specjalizowany może zwracać dwa rodzaje zawartości:

* Adres URL zasobu,
* Zawartość do osadzenia w prezentowanym wniosku.

#### Adres URL zasobu

Usługa zwracająca adres URL zasobu odpowiada jednowierszowym komunikatem postaci:

```
URL:adresUrlZasobu
```

Przykładowo:

```
URL:http://adres.serwera.obrazkow/zdjecie.png
```

Komponent specjalizowany zasilony adresem prezentuje statyczną zawartość.

#### Zawartość do osadzenia w prezentowanym wniosku

Treść zwrócona przez usługę zostanie osadzona bezpośrednio w prezentowanym wniosku. Komponent specjalizowany może przybierać postać:

* dokumentu HTML,
* skryptu JavaScript:
  * zapisane w tagach \<script>...\</script>
    * możliwe podanie wielu kolejnych tagów \<script /> jeden po drugim
  * zapisane w tagach \<script src="..." />
    * możliwe podanie wielu kolejnych tagów \<script /> jeden po drugim
* kombinacji dokumentu HTML i tagów \<script />.

Aplikacja **eximee WebForms** domyślnie dostarcza bibliotekę *jQuery,* którą można wykorzystać podczas projektowania komponentu specjalizowanego. Zewnętrzne biblioteki należy dostarczyć samodzielnie dodając odpowiednie tagi \<script src="..." />.

Przygotowany komponent specjalizowany jest osadzany bezpośrednio w drzewie DOM prezentowanego wniosku, a w trakcie renderowania na wszystkich tagach \<script />, wywoływana jest instrukcja *eval*.

#### Zapis wartości komponentu specjalizowanego

Komponent specjalizowany może stanowić bogatą aplikację napisaną w języku JavaScript, która może uaktualniać model wniosku o swoją wartość. W ten sposób, zapisana wartość jest uwzględniana podczas wyliczania warunków komponentów, aktualizacji komponentów zależnych, zasilania usług, zapisywania przy wysyłaniu wniosku itd.

W celu ustawienia wartości komponentu specjalizowanego należy wywołać globalną metodę dostarczaną przez aplikację **eximee WebForms:**

```
updateExternalSectionValue(IdentyfikatorKomponentSpecjalizowanego, NowaWartośćKomponentu);
updateExternalSectionValue(externalSection.attr('id'), 'newValue');
```

{% hint style="info" %}
Konstrukcja externalSection.attr('id') oznacza, że na węźle drzewa DOM odpowiadającemu komponentowi specjalizowanemu ustawiony jest atrybut id = identyfikator komponentu specjalizowanego.
{% endhint %}

Jej wywołanie powoduje uaktualnienie modelu prezentowanego wniosku oraz powiadomienie o zmianach wszystkich komponentów zależnych od komponentu specjalizowanego.

### Integracja na poziomie frontendu aplikacji

API komponentów specjalizowanych umożliwia między innymi integrację z aplikacją, w której osadzony jest wniosek (np. w przypadku kanału WWW osadzonego jako element portalu) na poziomie JavaScript. API dostarcza metod do odczytu oraz zapisu stanu komponentów na wniosku.

#### Pobranie wartości innego komponentu

W celu pobrania wartości innego komponentu należy ze skryptu ExternalSection wywołać funkcję getComponentValue("ID\_KOMPONENTU\_KTÓREGO\_WARTOŚĆ\_CHCEMY\_ODCZYTAĆ"), np:

```
var textfieldValue = getComponentValue("GesTextField1");
```

Należy jednak mieć na uwadze następujące ograniczenia:

* Chcąc czytać zmienne sesyjne, muszą one mieć zaznaczoną właściwość "exposed",
* Można czytać jedynie model kliencki - tzn. komponenty z już odwiedzonych stron, potencjalnie niezwalidowane pola.

#### Ustawienie wartości innego komponentu ze skryptu

Wszystkie pola, które mogą być zmieniane przez kod komponentu specjalizowanego, muszą być dodane do parametru *writableFields* komponentu, który ustawiamy na wniosku w zakładce **Źródło**. Żądanie zmiany wartości komponentu nie ujętego w parametrze *writableFields,* zostanie zignorowane przez platformę.

W celu ustawienia wartości innym komponentom z javascriptu należy wywołać poniższą funkcję:

```
/**
 * @param externalSectionId - id externalSection, które będzie chciało zawołać setComponentValue
 * @param componentId - id komponentu, któremu chcemy ustawić nową wartość. Do każdego komponentu webformsy wysyłają go automatycznie pod kluczem componentId
 * @param newValue - nowa wartość dla tego komponentu
 */
setComponentValue(externalSectionId,componentId, newValue);
```

Do zbioru komponentów, którym możemy ustawić nową wartość, należą:

* GesTextField
* GesRadioGroup (ważne! aby ustawiać wartość, która jest w dziedzinie radiogrupy. W innym wypadku otrzymamy błąd na wniosku).
* GesCheckboxSection
* GesCheckbox
* GesTextArea
* GesStatementPopup
* Combobox (id itemu, który chcemy ustawić)
* Slider (wartość z odpowiedniego przedziału)
* StepSlider (wartość z odpowiedniego przedziału)
* PlusMinus (wartość z odpowiedniego przedziału)
* DatePicker (wartość Long)

Parametry funkcji *setComponentValue* to **Stringi**. Poniżej zamieszczono przykładowe wywołanie funkcji:

```
setComponentValue('GesComplexComponent1.GesExternalSection1','GesComplexComponent1.GesTextField3', 'aaaaaa');
```

Przekazywanie wartości do GesStatementPopup:

* wartość powinna być łańcuchem znaków zawierającym obiekt JSON o następującej strukturze: { MID\_OŚWIADCZENIA1 : wartość, MID\_OŚWIADCZENIA2 : wartość ... }
* wartość przekazana w obiekcie musi być typu boolean (true / false)
* zostaną zmienione jedynie w obiekcie
* przykładowe wywołanie:

  ```
  setComponentValue('GesComplexComponent1.GesExternalSection1','GesComplexComponent1.GesStatementPopup1', '{ "GesComplexComponent1.item1": true }')
  ```


---

# 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/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponent-specjalizowany-externalsection.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.
