# Slider

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

Komponent pozwalający na wybranie wartości numerycznych przy pomocy suwaka.

![](https://content.gitbook.com/content/2CssJT0zIo4SJQLbSZ6l/blobs/UQI2VkKvY5L8AgnSm0Fl/14s_files/image2025-5-16_10-39-8.png)

✅ **Kiedy stosować:**

* Gdy chcesz pozwolić na wpisanie dowolnej, precyzyjnej kwoty w polu tekstowym (np. kwota kredytu 5200 PLN), niezależnie od kroku suwaka (np. 500 PLN).
* Gdy potrzebujesz wizualnie ograniczyć zakres wyboru bez zmiany widocznej skali – właściwości `minBlockValue` i `maxBlockValue` pozwalają na dynamiczną blokadę suwaka (np. na podstawie zdolności kredytowej klienta formularz ogranicza zakres do 5000 PLN, mimo że maksymalna kwota oferowana przez bank to 10 000 PLN).

:x: **Kiedy nie stosować:**

* Gdy proces nie pozwala na stosowanie wartości pośrednich (np. wniosek dopuszcza tylko konkretne wartości, np. liczbę rat). **Stosuj**: [Step Slider](https://docs.eximee.com/budowanie-aplikacji/interfejs-uzytkownika/formularze/biblioteka-komponentow-bazowych/3-wartosci-i-skale/step-slider).

## Właściwości komponentu

| **Właściwość Eximee Designer**                                                        | Nazwa atrybutu w Źródle | **Opis**                                                                                                                                                                                                                                                          |
| ------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Krok, co jaki można ustawić wartość na suwaku** (sekcja **Podstawowe właściwości**) | step                    | Skok wartości, czyli krok, co jaki można ustawić wartość na suwaku (domyślnie wartość 100).                                                                                                                                                                       |
| **Wartość startowa suwaka** (sekcja **Podstawowe właściwości**)                       | startValue              | Wartość startowa suwaka (domyślnie pusta). Może być zasilona z usługi.                                                                                                                                                                                            |
| **Minimalna prezentowana wartość suwaka** (sekcja **Podstawowe właściwości**)         | minValue[^1]            | Wartość minimalna suwaka (domyślnie wartość 0). Może być zasilona z usługi.                                                                                                                                                                                       |
| **Maksymalna prezentowana wartość suwaka** (sekcja **Podstawowe właściwości**)        | maxValue[^1]            | Wartość maksymalna suwaka (domyślnie wartość 1000). Może być zasilona z usługi.                                                                                                                                                                                   |
| **Minimalna możliwa wartość** (sekcja **Podstawowe właściwości**)                     | minBlockValue[^1]       | Minimum, poza które nie będzie można wybrać wartości (domyślna wartość 0). Może być zasilona z usługi.                                                                                                                                                            |
| **Maksymalna możliwa wartość** (sekcja **Podstawowe właściwości**)                    | maxBlockValue[^1]       | Maksimum, poza które nie będzie można wybrać wartości (domyślna wartość 1000). Może być zasilona z usługi.                                                                                                                                                        |
| **Wartość sugerowana** (sekcja **Podstawowe właściwości**)                            | suggestedValue          | Wartość sugerowana (np. w przypadku limitu odnawialnego wysokość limitu sugerowana przez bank). Może być zasilona z usługi. Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.                                      |
| **Suffix etykiety minimalnej i maksymalnej wartości suwaka** (sekcja **Pozostałe**)   | legendSuffix            | Wartość "doklejana" do etykiety minimalnej i maksymalnej wartości slidera. Może być zasilona z usługi. Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.                                                           |
| **Prognozowana wartość suwaka po najechaniu na oś** (sekcja **Pozostałe**)            | showPredictionTooltip   | Pokazywanie prognozowanej wartości suwaka po najechaniu na oś suwaka (domyślna wartość "true"). Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.                                                                  |
| **Prezentacja w dymku wartości wskazywanej przez suwak** (sekcja **Pozostałe**)       | showTooltip             | Pokazanie wartości wskazywanej przez suwak (domyślna wartość "true"). Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.                                                                                            |
| **Formatter wartości wyświetlanej w polu tekstowym**                                  | textInputFormatter      | Formatter wartości wyświetlanej w polu tekstowym slidera. Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniami.                                                                                                        |
| **Suffix pola tekstowego**                                                            | textInputSuffix         | Wartość "doklejana" na końcu pola tekstowego slidera. Może być zasilona z usługi. Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.                                                                                |
| **Opis wyświetlany po kliknięciu w pole tekstowe**                                    | descriptionPopupText    | Opis wyświetlany po kliknięciu w pole tekstowe slidera. Funkcjonalność dostępna w kanale mobilnym i native.                                                                                                                                                       |
| **Komunikat przekroczenia wartości minimalnej**                                       | minValueSuggest         | Tekst wyświetlany pod polem tekstowym slidera po przekroczeniu wartości minimalnej. Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.                                                                              |
| **Komunikat przekroczenia wartości maksymalnej**                                      | maxValueSuggest         | Tekst wyświetlany pod polem tekstowym slidera po przekroczeniu wartości maksymalnej. Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.                                                                             |
| **Synchronizacja stanu suwaka i wartości wpisanej w polu tekstowym**                  | separatedSliderValue    | Steruje synchronizacją stanu suwaka i wartości wpisanej w inpucie. Przy separatedSliderValue=true nie są respektowane wartości minBlockValue oraz maxBlockValue. Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach. |

{% hint style="warning" %}
WAŻNE — na Sliderze domyślnie wartości maxValue i maxBlockValue powinny się pokrywać, chyba że celowo mają się różnić (wtedy wartość Slidera będzie ograniczana do min (maxBlockValue, maxValue), więc górnym ograniczeniem będzie najmniejsza z tych wartości.). Analogicznie z wartościami minValue i minBlockValue.

W komponencie Slidera (we właściwościach) nie ma możliwości ustawienia wartości startowej/minimalnej/maksymalnej na wartości innego typu niż integer.
{% endhint %}

> 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)

## Przepisanie wartości slidera do Pola tekstowego (TextFielda) i odwrotnie

Jeśli wartość Slidera ma zostać przepisana do komponentu Pole tekstowe, komponent ten musi nasłuchiwać na Slider, a przepisanie wartości nastąpi albo przez wskazanie slidera w **Źródło danych z innego pola** komponentu tekstowego, albo dla Pola tekstowego zostanie ustawiona specjalna usługa (np. *EchoService*).

Także wartość Slidera może zostać ustawiona na podstawie liczby wpisanej do komponentu Pole tekstowe. W tym celu należy Sliderem nasłuchiwać na TextField i wskazać to pole tekstowe we właściwości **Źródło danych z innego pola** Slidera.

### Slider z przykładowymi właściwościami

![Ilustracja 1. Przykładowy wygląd komponentu na wniosku](https://content.gitbook.com/content/2CssJT0zIo4SJQLbSZ6l/blobs/Ne5vZpyuT1T0Oa4xtcAR/14s_files/image2025-5-16_10-43-44.png)

### Specyficzny wygląd Slidera

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

W niektórych szatach pole tekstowe jest już zintegrowane ze sliderem.

![Ilustracja 2. Przykładowy wygląd Slidera z polem tekstowym](https://content.gitbook.com/content/2CssJT0zIo4SJQLbSZ6l/blobs/5Czmt061WYddAQzGcAlc/14s_files/image2025-5-16_10-44-29.png)

![Ilustracja 3. Przykładowy wygląd Slidera z parametrami podawanymi w polach tekstowych](https://content.gitbook.com/content/2CssJT0zIo4SJQLbSZ6l/blobs/XXaLQPx9gGo3SRtYVCnr/14s_files/image2025-5-16_10-46-11.png)

## Informacje o stanie komponentu

Informacje o aktualnej wartości danej właściwości komponentu, którą można następnie wykorzystać na wniosku np. do zasilenia innego pola wartością tej właściwości, można uzyskać stosując konstrukcję ID\_COMPONENTU$NAZWA\_WŁAŚCIWOŚCI

Dla slidera można pobrać następującą właściwość:

| Klucz           | Opis                                                                                                                      |
| --------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **sliderValue** | Wartość oznaczona na suwaku. W przypadku oznaczenia separatedSliderValue na true, może różnić się od wartości komponentu. |

{% hint style="info" %}
Przykład: zasilenie **Źródło danych z innego pola** poprzez GesSlider1$sliderValue
{% endhint %}

## Przykładowy walidator dla Slidera

Walidator wyświetla hint dla Slidera w określonych sytuacjach.

Podczas podłączania poniższego walidatora należy jako parametr *insuranceComponentId* wpisać id komponentu odnoszącego się do ubezpieczenia (np. checkboxa sterującego włączeniem/wyłączeniem ubezpieczenia) oraz jako *sliderId* podać id Slidera, na którym kwotami chcemy sterować. Jeśli wymienione komponenty nie są osadzone bezpośrednio na wniosku, to należy podać pełną ścieżkę osadzenia, czyli id komponentu złożonego, w którym znajdują się te komponenty oraz każdego komponentu złożonego nadrzędnego.

<details>

<summary>Przykładowy kod walidatora</summary>

{% code title="DevDemoSliderHintValidator.java" %}

```java
package pl.slider.demo.hint;

import lombok.extern.slf4j.Slf4j;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pl.consdata.eximee.validation.api.exceptions.ValidatorException;
import pl.consdata.eximee.validation.api.model.*;
import pl.consdata.eximee.validation.api.validator.AbstractExtendedValidator;

import java.math.BigDecimal;

import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.apache.commons.lang3.StringUtils.*;

@Slf4j
@Component
@Service(AbstractExtendedValidator.class)
public class DevDemoSliderHintValidator extends AbstractExtendedValidator {
    static final String GREATER_THAN_MAX = "DevDemoSliderHintValidator.greaterThanMax";
    static final String LESS_THAN_MIN = "DevDemoSliderHintValidator.lessThanMin";
    static final String LESS_THAN_MIN_BUTTON_LABEL = "DevDemoSliderHintValidator.lessThanMin.buttonLabel";
    static final String GREATER_THAN_MAX_BUTTON_LABEL = "DevDemoSliderHintValidator.greaterThanMax.buttonLabel";
    static final String GREATER_THAN_INSURANCE_TRESHOLD_CHANGE_AMOUNT = "DevDemoSliderHintValidator.greaterThanInsuranceTreshold.changeAmount";
    static final String GREATER_THAN_INSURANCE_TRESHOLD_WITHOUT_INSURANCE = "DevDemoSliderHintValidator.greaterThanInsuranceTreshold.withoutInsurance";
    static final String INSURANCE_AMOUNT_THRESHOLD = "insuranceAmountThreshold";
    static final String MAX_AMOUNT = "maxAmount";
    static final String MIN_AMOUNT = "minAmount";
    static final String SLIDER_INPUT = "sliderInput";
    static final String INSURANCE_CURRENT_VALUE = "insuranceCurrentValue";
    static final String INSURANCE_COMPONENT_ID = "insuranceComponentId";
    static final String INSURANCE_UNCHECKED_VALUE = "insuranceUncheckedValue";
    static final String GREATER_THAN_INSURANCE_TRESHOLD = "DevDemoSliderHintValidator.greaterThanInsuranceTreshold";
    static final String SLIDER_ID = "sliderId";

    private static final Logger LOGGER = LoggerFactory.getLogger(DevDemoSliderHintValidator.class);

    public DevDemoSliderHintValidator() {
        this.name = "DevDemoSliderHintValidator";
        this.version = "1.0";
        this.description = "Walidator zwracający komunikat walidacyjny w formie hinta dla slidera.";
        this.fields.put(SLIDER_INPUT, "Wartość ze slidera");
        this.fields.put(SLIDER_ID, "Identyfikator walidowanego slidera");
        this.fields.put(INSURANCE_AMOUNT_THRESHOLD, "Próg dla kwoty z ubezpieczeniem");
        this.fields.put(MAX_AMOUNT, "Maksymalna wartość w sliderze");
        this.fields.put(MIN_AMOUNT, "Minimalna wartość w sliderze");
        this.fields.put(INSURANCE_CURRENT_VALUE, "Aktualna wartość ubezpieczenia");
        this.fields.put(INSURANCE_COMPONENT_ID, "Identyfikator komponentu ubezpieczenia");
        this.fields.put(INSURANCE_UNCHECKED_VALUE, "Wartość niezaznaczonego ubezpieczenia");

        this.possibleErrors.put(LESS_THAN_MIN, "Minimalna kwota pożyczki to <strong>{0} PLN</strong>");
        this.possibleErrors.put(GREATER_THAN_MAX, "Dla pożyczki wyższej niż <strong>{0} PLN</strong> na rękę musimy zadać Ci kilka dodatkowych pytań.");
        this.possibleErrors.put(GREATER_THAN_INSURANCE_TRESHOLD, "Jeżeli chcesz pożyczkę z ubezpieczeniem wyższą niż <strong>{0} PLN</strong> na rękę, odwiedź dowolny oddział Banku.");
        this.possibleErrors.put(LESS_THAN_MIN_BUTTON_LABEL, "Rozumiem >");
        this.possibleErrors.put(GREATER_THAN_MAX_BUTTON_LABEL, "Tak, chcę wnioskować o {1} PLN");
        this.possibleErrors.put(GREATER_THAN_INSURANCE_TRESHOLD_CHANGE_AMOUNT, "Zmniejszam kwotę");
        this.possibleErrors.put(GREATER_THAN_INSURANCE_TRESHOLD_WITHOUT_INSURANCE, "Bez ubezpieczenia");
    }

    @Override
    public ValidatorOutput validate(ValidatorInput validatorInput) {
        LOGGER.info(">> Validator called with params: {}", validatorInput);
        ValidatorOutput result = new ValidatorOutput();

        if (isValueGreaterThanMax(validatorInput)) {
            result.setErrors(singletonList(valueGreaterThanMaxMessage(validatorInput)));
        } else if (isValueLessThanMin(validatorInput)) {
            result.setErrors(singletonList(valueLessThanMinMessage(validatorInput)));
        } else if (isValueGreaterThanInsuranceTresholdAndInsuranceIsChecked(validatorInput)) {
            result.setErrors(singletonList(valueGreaterThanInsuranceTresholdAndInsuranceIsCheckedMessage(validatorInput)));
        }

        LOGGER.info("<< Output: {}", result);
        return result;
    }

    private boolean isValueGreaterThanMax(final ValidatorInput input) {
        return asBigDecimal(input.getFirstValue(SLIDER_INPUT)).compareTo(asBigDecimal(input.getFirstValue(MAX_AMOUNT))) > 0;
    }

    private ValidationMessage valueGreaterThanMaxMessage(final ValidatorInput input) {
        final ValidationMessage message = new ValidationMessage(GREATER_THAN_MAX, asList(input.getFirstValue(MAX_AMOUNT), input.getFirstValue(SLIDER_INPUT)));
        message.setType(ValidationMessage.TYPE_HINT);
        message.setActions(singletonList(ValidationAction
                .builder()
                .actionData("https://www.xxxxxxx.pl")
                .actionType(ValidationActionType.REDIRECT)
                .actionName(GREATER_THAN_MAX)
                .content(GREATER_THAN_MAX_BUTTON_LABEL)
                .build()));
        return message;
    }

    private boolean isValueLessThanMin(final ValidatorInput input) {
        return asBigDecimal(input.getFirstValue(SLIDER_INPUT)).compareTo(asBigDecimal(input.getFirstValue(MIN_AMOUNT))) < 0;
    }

    private ValidationMessage valueLessThanMinMessage(final ValidatorInput input) {
        final ValidationMessage message = new ValidationMessage(LESS_THAN_MIN, singletonList(input.getFirstValue(MIN_AMOUNT)));
        message.setType(ValidationMessage.TYPE_HINT);
        message.setActions(singletonList(ValidationAction
                .builder()
                .actionData(input.getFirstValue(MIN_AMOUNT))
                .actionType(ValidationActionType.CHANGE_VALUE)
                .changeComponentId(input.getFirstValue(SLIDER_ID))
                .actionName(LESS_THAN_MIN)
                .content(LESS_THAN_MIN_BUTTON_LABEL)
                .build()));
        return message;
    }

    private boolean isValueGreaterThanInsuranceTresholdAndInsuranceIsChecked(final ValidatorInput input) {
        return !equalsIgnoreCase(input.getFirstValue(INSURANCE_CURRENT_VALUE), input.getFirstValue(INSURANCE_UNCHECKED_VALUE))
                && asBigDecimal(input.getFirstValue(SLIDER_INPUT)).compareTo(asBigDecimal(input.getFirstValue(INSURANCE_AMOUNT_THRESHOLD))) > 0;
    }

    private ValidationMessage valueGreaterThanInsuranceTresholdAndInsuranceIsCheckedMessage(final ValidatorInput input) {
        final ValidationMessage message = new ValidationMessage(GREATER_THAN_INSURANCE_TRESHOLD, singletonList(input.getFirstValue(INSURANCE_AMOUNT_THRESHOLD)));
        message.setType(ValidationMessage.TYPE_HINT);
        message.setActions(asList(ValidationAction
                .builder()
                .actionData(input.getFirstValue(INSURANCE_AMOUNT_THRESHOLD))
                .actionType(ValidationActionType.CHANGE_VALUE)
                .changeComponentId(input.getFirstValue(SLIDER_ID))
                .actionName(GREATER_THAN_INSURANCE_TRESHOLD_CHANGE_AMOUNT)
                .content(GREATER_THAN_INSURANCE_TRESHOLD_CHANGE_AMOUNT)
                .build(), ValidationAction
                .builder()
                .actionData(input.getFirstValue(INSURANCE_UNCHECKED_VALUE))
                .actionType(ValidationActionType.CHANGE_VALUE)
                .changeComponentId(input.getFirstValue(INSURANCE_COMPONENT_ID))
                .actionName(GREATER_THAN_INSURANCE_TRESHOLD_WITHOUT_INSURANCE)
                .content(GREATER_THAN_INSURANCE_TRESHOLD_WITHOUT_INSURANCE)
                .build()));
        return message;
    }

    private BigDecimal asBigDecimal(final String str) {
        final String digits = removePattern(str, "[^0-9-]");
        return isNotEmpty(digits) ? new BigDecimal(digits) : BigDecimal.ZERO;
    }
}
```

{% endcode %}

</details>

{% hint style="info" %}
Wniosek demo: demoSlider

Wniosek demo w wybranych wdrożeniach: demoSliderValidationHint
{% 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 %}

[^1]: Wartość Slidera będzie ograniczana do min (maxBlockValue, maxValue), więc górnym ograniczeniem będzie najmniejsza z tych wartości.
