Jak w JavaScript uzależnić wartości dwóch pól select od siebie?

Treść dodana: 10 listopada 2017. Ostatnia modyfikacja: 10 listopada 2017.

Dość częstym problemem spotykanym w trakcie generowania kodu HTML są zależne od siebie różne wartości pól `select` lub `checkbox`. Kombinacji może być kilka:

  1. ta sama wartość w identycznych polach, w kilku miejscach na stronie
  2. zmiana jednego pola `select` spowoduje wybranie innej wartości w kolejnym polu
  3. zmiana pola `select` spowoduje wygenerowanie nowych wartości w drugim polu

Dla ułatwienia posłużę się popularną biblioteką jQuery w najnowszej wersji (obecnie v3). Przyda się również znajomość delegacji zdarzeń.

Wariant 1

Wariant ten zakłada sytuację w której na stronie jest kilka identycznych pól `select` i zmiana któregokolwiek z nich spowoduje zmiany w pozostałych polach. Przykładowy kod HTML może wyglądać następująco:

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>Przykład - wariant 1</title>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script>
        $(function() {
            // kod w tym miejscu zostanie wykonany po załadowaniu drzewa DOM
        });
    </script>
</head>
<body>
    <main>
        <select name="v1" class="wariant1">
            <option value="1">Opcja 1</option>
            <option value="2">Opcja 2</option>
            <option value="3">Opcja 3</option>
        </select>

        <select name="v2" class="wariant1">
            <option value="1">Opcja 1</option>
            <option value="2">Opcja 2</option>
            <option value="3">Opcja 3</option>
        </select>
    </main>
</body>
</html>

Najłatwiej w takiej sytuacji będzie nadać obu polom taką samą klasę – w naszym przypadku `.wariant1`. Następnie przypinamy do wszystkich pól reakcję na zdarzenie `change`:

$(function() {
    var select = $('select.wariant1');
    select.on('change', function(event) {
        event.preventDefault();
        select.prop('selectedIndex', $(this).prop('selectedIndex'));
    });
});

Właściwość `selectedIndex` zawiera numeryczną wartość wybranego indeksu (pola `option`). Pobieramy ją z danego pola `select` i ustawiamy identyczną pozostałym. Jest to najprostszy przykład użycia.

Wariant 2

Drugi wariant zakłada sytuację, w której wybór wartości w pierwszym polu `select` spowoduje wybranej innej wartości w polu drugim. Przykładowy HTML:

    <main>
        <select name="v1" class="wariant2">
            <option value="1">Opcja 1</option>
            <option value="2">Opcja 2</option>
            <option value="3">Opcja 3</option>
        </select>

        <select name="v2" class="wariant2">
            <option data-bind="1" value="1">Opcja 1</option>
            <option data-bind="2" value="2">Opcja 2</option>
            <option data-bind="0" value="3">Opcja 3</option>
        </select>
    </main>

Oprócz tego że nadana została inna klasa `wariant2`, drugi `select` zawiera atrybut `data-bind` definiujący wartość powiązaną z pierwszym polem. Innymi słowy, wybrana wartość z pierwszego selecta spowoduje wybranie wartości odpowiadającej atrybutowi `data-bind` w selekcie numer dwa. Wartość `selectedIndex` zaczyna się od 0.

$(function() {
    var select1 = $('select[name="v1"].wariant2');
    var select2 = $('select[name="v2"].wariant2');
    select1.on('change', function(event) {
        event.preventDefault();
        select2.children('option[data-bind='+ $(this).prop('selectedIndex') +']').prop('selected', true);
    });
});

Przy zmianie wartości `selectedIndex` pierwszego selekta, wybieramy pole `option` posiadające odpowiadającą mu wartość atrybutu `data-bind` z selekta drugiego i ustawiamy jako wybrane.

Wariant 3

Wariant trzeci jest najtrudniejszy pod względem kodu. Zakłada sytuację w której posiadamy tylko jeden `select` oraz po stronie JS tablicę wartości, która utworzy dynamicznie drugi `select`.

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>Przykład - wariant 3</title>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script>
        var select2Data = {
            1: [
                {value: '1_1', text: 'Wartość 1_1'},
                {value: '1_2', text: 'Wartość 1_2'},
                {value: '1_3', text: 'Wartość 1_3'}
            ],
            2: [
                {value: '2_1', text: 'Wartość 2_1'},
                {value: '2_2', text: 'Wartość 2_2'},
                {value: '2_3', text: 'Wartość 2_3'}
            ],
            3: [
                {value: '3_1', text: 'Wartość 3_1'},
                {value: '3_2', text: 'Wartość 3_2'},
                {value: '3_3', text: 'Wartość 3_3'}
            ]
        }
        $(function() {
        });
            </script>
</head>
<body>
    <main>
        <select name="v1" class="wariant3">
            <option value="1">Opcja 1</option>
            <option value="2">Opcja 2</option>
            <option value="3">Opcja 3</option>
        </select>
    </main>
</body>
</html>

Zmienna `select2Data` zawiera tablicę obiektów dla poszczególnych wybranych opcji. Dla odmiany zastosowaliśmy indeks liczony od 1 co oznacza, iż należy to dodatkowo uwzględnić w kodzie.

$(function() {
    var generateSelect = function(index) {
        $('#generated').remove();
        var select = $('<select/>', {
            id: 'generated',
            name: 'v2',
            html: $.map(select2Data[index], function(v) {
                return $('<option/>', {
                    text: v.text,
                    value: v.value
                });
            })
        });
        select.appendTo('body > main');
    };
    $('select[name="v1"].wariant3').on('change', function(event) {
        event.preventDefault();
        generateSelect($(this).prop('selectedIndex')+1);
    });
});

Kodu tym razem jest trochę więcej. Po zmianie wartości naszego pola `select` wywoływana jest funkcja `generateSelect` do której przekazujemy aktualny indeks powiększony o 1. Jest to indeks obiektu `select2Data` czyli tablica wartości dla danego indeksu. Sama funkcja `generateSelect` na początku usuwa dynamicznie wygenerowany element (#generated), następnie tworzy nowy `select` o takim identyfikatorze, nadaje mu `name` = v2. Jako HTML generujemy pola `option` bazujące na tablicy `select2Data`. Jeśli nie wiesz Czytelniku co dane zmienne zawierają pamiętaj, że w każdym miejscu w kodzie możesz wywołać polecenie:

console.log(zmienna);

które wyświetli w konsoli przeglądarki wartość zmiennej. Cały nowo utworzony `select` dodawany jest do elementu `body > main`.

Podsumowanie

Mam nadzieję że artykuł wyjaśnił trochę zawiłości tworzenia i oddziaływania pól na siebie. Przy niewielkim nakładzie pracy można uzyskać naprawdę ciekawe efekty. Jeśli masz Czytelniku pytania albo nasunął Ci się pomysł na kolejny wariant zapraszam do komentowania.

Komentarze

Nie ma jeszcze żadnych komentarzy do wyświetlenia. Może chcesz zostać pierwszą osobą która podzieli się swoją opinią?

Dodaj komentarz

*
Nazwa zostanie wyświetlona wraz z komentarzem. Możesz też utworzyć nowe konto w serwisie, dzięki czemu uzyskasz dodatkową funkcjonalność.
*
Akceptowana jest ograniczona składnia Textile. Wszystkie tagi HTML zostaną usunięte.