# Sekcja powtarzalna - RepeatableSection

Zestaw pól, które mogą być wielokrotnie wypełnione we wniosku przez użytkownika.

![](https://content.gitbook.com/content/2CssJT0zIo4SJQLbSZ6l/blobs/hzYmMQfUhU0Ho5gnZCnD/21s_files/image2025-5-16_11-47-17.png)

## Właściwości komponentu

<table><thead><tr><th>Właściwość Eximee Designer</th><th width="187.583251953125">Nazwa atrybutu w Źródle</th><th>Opis</th></tr></thead><tbody><tr><td><strong>Minimalna liczba wystąpień sekcji</strong><br>(sekcja <strong>Podstawowe właściwości</strong>)</td><td>minCount</td><td>Minimalna liczba wystąpień sekcji powtarzalnej (początkowa wartość 1). W chwili wyświetlania wniosku jest to także liczba wystąpień, które są domyślnie widoczne i dostępne. Usuwając elementy sekcji podczas wypełniania wniosku nie można zejść poniżej tej liczby.</td></tr><tr><td><strong>Maksymalna liczba wystąpień sekcji</strong><br>(sekcja <strong>Podstawowe właściwości</strong>)</td><td>maxCount</td><td>Maksymalna liczba wystąpień sekcji powtarzalnej (początkowa wartość 1). Dodając elementy sekcji nie można przekroczyć tej liczby.</td></tr><tr><td><strong>Tytuł</strong><br>(sekcja <strong>Podstawowe właściwości</strong>)</td><td>title</td><td><p>Tytuł.</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Tytuł całej sekcji powtarzalnej</strong><br>(sekcja <strong>Podstawowe właściwości</strong>)</td><td>parentSectionTitle</td><td>Tytuł dla całej sekcji powtarzalnej.</td></tr><tr><td><strong>Etykieta przycisku zwinięcia sekcji</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td></td><td><p>Etykieta przycisku zwinięcia sekcji.</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Etykieta przycisku rozwinięcia sekcji</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td></td><td><p>Etykieta przycisku rozwinięcia sekcji.</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Sekcja zwijana</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>foldable</td><td><p>Określa czy sekcja powinna mieć możliwość zwinięcia (początkowo ustawiona na "false").</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Warunek zwinięcia sekcji</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>foldedCondition</td><td><p>Warunek zwinięcia sekcji.</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniami.</p></td></tr><tr><td><strong>Sposób prezentacji rozwijania sekcji</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>presentation</td><td><p>Określenie sposobu prezentacji rozwijania sekcji. Dostępne typy prezentacji zwijania/rozwijania: STANDARD i LABELS (poniżej szerszy opis).</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Dynamiczne etykiety przycisków</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>plusMinusLabels</td><td>Warunki dla widoczności przycisków dodawania/usuwania elementów sekcji powtarzalnej.</td></tr><tr><td><strong>Etykieta przycisku usunięcia sekcji</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>minusText</td><td>Etykieta dla przycisku minus (usunięcie elementu sekcji powtarzalnej).</td></tr><tr><td><strong>Etykieta przycisku dodania sekcji</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>plusText</td><td>Etykieta dla przycisku plus (dodanie elementu sekcji powtarzalnej).</td></tr><tr><td><strong>Tytuł rozwijanej sekcji</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>rowTitleExpanded</td><td><p>Tytuł wyświetlany dla rozwiniętej sekcji.</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Tytuł zwiniętej sekcji</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>rowTitleCollapsed</td><td><p>Tytuł wyświetlany dla zwiniętej sekcji.</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Obramowanie komponentu</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>parentSectionFrameVisible</td><td><p>Ustawienie flagi powoduje wyświetlenie ramki wokół wszystkich wystąpień sekcji powtarzalnej (początkowo ustawiona na "false").</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Wartość przesunięcia przycisku dodawania</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>plusButtonOffset</td><td><p>Wartość przesunięcia przycisku dodawania (początkowo ustawiona na 0).</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p></td></tr><tr><td><strong>Pomoc kontekstowa przycisku usuwania</strong><br>(sekcja <strong>Pozostałe</strong>)</td><td>minusToolTipText</td><td>Pomoc kontekstowa przycisku usuwania wiersza</td></tr></tbody></table>

> Więcej informacji o właściwościach komponentu: [Wspólne właściwości komponentów](https://docs.eximee.com/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/wspolne-wlasciwosci-komponentow)

## Praca z sekcją powtarzalną

Umieszczenie sekcji powtarzalnej na szablonie wniosku powoduje dodanie obszaru, z którym można pracować podobnie jak z całym wnioskiem. Oznacza to, że obszar ten ma swój własny układ strony i może zawierać dowolną liczbę komponentów bazowych. W przykładzie na rysunku wystąpienie sekcji powtarzalnej skonfigurowane zostało jako kompozyt składający się z pola tekstowego i pól wyboru wartości z listy z etykietami. Znak plus/minus w prawym dolnym rogu służy do dodawania kolejnych wierszy sekcji.

W wynikowym wniosku wystąpienia sekcji powtarzalnej wyświetlane są zgodnie z konfiguracją. Użytkownik ma możliwość usuwania bądź dodawania wystąpień, używając odpowiednio przycisku **minus** oraz **plus**.

<figure><img src="https://content.gitbook.com/content/2CssJT0zIo4SJQLbSZ6l/blobs/YBk7oFeuv7ywFUWuBLPp/21s_files/image2025-5-16_11-47-57.png" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Przykładowy wygląd komponentu na wniosku.</em></p></figcaption></figure>

{% hint style="warning" %}
W Repeatable Section nie można użyć [zmiennych sesyjnych](https://docs.eximee.com/budowanie-aplikacji/interfejs-uzytkownika/formularze/zmienne-sesyjne) — tutaj używamy pól technicznych (np. komponent Pole tekstowe z zaznaczoną właściwością [Pole techniczne](https://docs.eximee.com/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/wspolne-wlasciwosci-komponentow)). Również zasilanie pól z usługi w sekcji powtarzalnej może powodować nietypowe błędy — np. nieprawidłowe wyświetlanie komponentów (ale nie musi). W takiej sytuacji należy zastosować obejście w postaci pola technicznego.
{% endhint %}

## Zasilenie sekcji powtarzalnej usługą

Zalecane jest, aby tworząc ServiceProxy dziedziczyć po klasie **AbstractRepeatableServiceProxy**. Klasa ta automatycznie zwraca 3 wartości: minCount, maxCount i count. Wartości te można ustawić lub nic z nimi nie robić — są one opcjonalne.

Przykładowe ServiceProxy:

* Są w nim dodane 2 pola wejściowe,
* Są w nim dodane 2 dodatkowe pola wyjściowe (**minCount**, **maxCount**, **count** dodane są w klasie wyżej),
* Aby ustawić parametry trzeba jedynie na modelu **RepeatableSectionMetadata** wywołać odpowiednie settery,
* Po ustawieniu powyższych parametrów, ustawiamy wartości które potem będziemy mapować na poszczególnych polach.

```java
@Component
@Service(AbstractServiceProxy.class)
public class RepeatableTestSp extends AbstractRepeatableServiceProxy {

    public RepeatableTestSp(String name, String description) {
        super("RepeatableTestSp", "Description...");
        this.inputFields.add(new ServiceProxyField("input1"));
        this.inputFields.add(new ServiceProxyField("input2"));
        this.outputFields.add(new ServiceProxyField("output1"));
        this.outputFields.add(new ServiceProxyField("output2"));
    }

    @Override
    protected RepeatableSectionMetadata callRepeatableSectionService(
            Map<String, List<String>> requestParams, String lang) throws ServiceProxyException {
        final RepeatableSectionMetadata repeatableSectionMetadata = new RepeatableSectionMetadata();
        repeatableSectionMetadata.setMinCount(1);
        repeatableSectionMetadata.setMaxCount(10);
        repeatableSectionMetadata.setCount(5);
        repeatableSectionMetadata.setRepeatableSectionRows(createRows());
        return repeatableSectionMetadata;
    }

    private List<Map<String, String>> createRows() {
        final List<Map<String, String>> rows = new ArrayList<>();
        rows.add(createRow());
        rows.add(createRow());
        return rows;
    }

    private Map<String, String> createRow() {
        final Map<String, String> map = new HashMap<>();
        map.put("output1", "1");
        map.put("output2", "abc");
        return map;
    }
}
```

Aby skorzystać z powyższego ServiceProxy, w **externalDataSource** powinien być typ **REPEATABLE\_SCECTION\_SERVICE**.

Podsumowując: usługa dodała 2 wiersze, jednak ustawiła wartość count na 5. Tak więc zostanie wyświetlone 5 wierszy, z czego tylko 2 się wypełnią zmapowaną wartością z endpointu output1.

{% hint style="info" %}
Istnieje również możliwość zasilenia sekcji powtarzalnej skryptem.
{% endhint %}

## Przykład sekcji powtarzalnej z wartościami do zsumowania

Gdy chcemy zsumować wartości z powtarzającego się komponentu GesTextField1 w sekcji powtarzalnej, tworzymy nowy GesTextField2 poza sekcją i podpinamy w **Źródle danych zewnętrznych** skrypt SumService:

```javascript
function callService(context) {
    let parts = context.getParameters('parts');
    
    let result = BigDecimal.valueOf("0");
    
    if (!!parts) {
        for (let i = 0; i < parts.size(); i++) {
            let part = parts.get(i);

            if(!!part){
                let bigDecimalItem = BigDecimal.valueOf(part.replace(',','.'));
                result = result.add(bigDecimalItem);
            }
        }
    }
    
    return [{'output': result.setScale(2)}];
}
```

W parametrach wejściowych skryptu podpinamy powtarzający się komponent z wartościami do zsumowania GesTextField1, a w parametrach wyjściowych wybieramy output, czyli sumę wartości, jako atrybut text.

<figure><img src="https://1082717226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2CssJT0zIo4SJQLbSZ6l%2Fuploads%2F6EIbQrxrzpbekDYZyQ3i%2Fobraz.png?alt=media&#x26;token=a5cae498-992b-4bb1-8868-f8f6af9d1070" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Podpięcie parametru wyjściowego w skrypcie SumService</em></p></figcaption></figure>

{% hint style="info" %}
Wnioski demo:

* demoRepeatableSection
* repeatable\_section\_service (wniosek pokazujący zasilenie sekcji usługą lub skryptem)
* demoRepeatableSectionValidator (wniosek z walidatorem dla powtarzających się wartości w sekcji)
  {% endhint %}

{% hint style="info" %}
♿WCAG: [Dobre praktyki WCAG dla low-code dev](https://docs.eximee.com/budowanie-aplikacji/proces-biznesowy/tworzenie-procesu-biznesowego-w-bpmn-2.0/dobre-praktyki)
{% endhint %}
