Dynamiczna lista wyboru w formularzu (lista rozwijana zależna)

28

Używam Drupal Seven. Chcę, aby opcje na liście wyboru były zależne od wartości wybranej na innej liście wyboru w formularzu. Jestem pewien, że już wiele razy o to pytano, ale mam trudności ze znalezieniem jasnej odpowiedzi na pytanie, jak to zrobić.

Formularz służy do wprowadzania historii pracy. Muszą wybrać eskadrę, która jest odniesieniem do węzła typu pola eskadry, a to znajduje się na liście rozwijanej. Eskadra zależy jednak od rozwijanej listy miast. Użytkownicy muszą najpierw wybrać miasto, które następnie przefiltruje opcje eskadry. W typie zawartości eskadry stworzyłem taksonomię dla miasta, która jest oznaczona jako eskadra.

Byłbym bardzo wdzięczny za wszelkie wskazówki dotyczące najlepszego (najprostszego?) Sposobu na rozwiązanie tego problemu lub za wszelkie przydatne zasoby online, które mogłyby pomóc.

Ben
źródło

Odpowiedzi:

27

Aby to zrobić, możesz użyć Ajax. Drupal 7 ma teraz dobrą obsługę Ajax. Na pierwszej wybranej liście (mieście) musisz dodać informacje Ajax. Następnie drugą listę wyboru można wypełnić na podstawie informacji z pierwszej. Możesz także ukryć drugą listę wyboru, dopóki nie zostanie wybrana opcja z pierwszej, a ja wyjaśnię, jak to zrobić za chwilę. Najpierw skonfiguruj podstawową formę:

$form['city'] = array(
  '#type' => 'select',
  '#title' => t('City'),
  '#options' => $options,
  '#ajax' => array(
    'event' => 'change',
    'wrapper' => 'squadron-wrapper',
    'callback' => 'mymodule_ajax_callback',
    'method' => 'replace',
  ),
);
$form['squadron_wrapper'] = array('#prefix' => '<div class="squadron-wrapper">', '#suffix' => '</div>');
$form['squadron_wrapper']['squadron'] = array(
  '#type' => 'select',
  '#title' => t('Squadron'),
  '#options' => $squadron_options,
);

To tylko podstawowa konfiguracja elementów. Teraz potrzebujesz sposobu, aby określić, jakie opcje powinny iść w eskadrze. Najpierw musisz zidentyfikować połączenie zwrotne Ajax na liście wyboru „miasto”. W większości przypadków możesz po prostu zwrócić element otaczający element ajax, w tym przypadku $ form.

function mymodule_ajax_callback($form, $form_state) {
  return $form;
}

Teraz, gdy zmieni się lista wyboru „miasto”, odbuduje część formularza zawierającą eskadrę. Twoja wartość „miasto” będzie teraz mieć wartość $ form_state [„wartości”]. Kiedy więc formularz zostanie przebudowany, musimy ustalić, jakie opcje dać wybranej liście na podstawie wartości „miasto”.

// Get the value of the 'city' field.
$city = isset($form_state['values']['city']) ? $form_state['values']['city'] : 'default';
switch ($city) {
  case 'default':
    // Set default options.
    break;
  case 'losangeles':
    // Set up $squadron_options for los angeles.
    break;
}

// If you want to hide the squadron select list until a city is
// selected then you can do another conditional.
if ($city !== 'default') {
  $form['squadron_wrapper']['squadron'] = array(
    '#type' => 'select',
    '#title' => t('Squadron'),
    '#options' => $squadron_options,
  );
}
jordojuice
źródło
6
Przykłady można znaleźć w module Przykłady („Przykłady AJAX” → „Lista rozwijana zależna”). Możesz również zobaczyć w module Hierarchical Select .
kalabro
Nawiasem mówiąc, alternatywnie możesz to zrobić w formie wieloetapowej, ale nie sądziłem, że zabrzmiało to tak, jak tego szukałeś. Również ^ dobre połączenie! Przykłady modułów są świetne do nauki tego rodzaju rzeczy.
jordojuice
@jordojuice Dziękuję bardzo za odpowiedź. Pracuję teraz nad tym. W trzecim przykładzie kodu, który podajesz powyżej (początek // Uzyskaj wartość ...), w której funkcji mam umieścić tę część kodu? Czy działa w funkcji _ajax_callback? Dzięki
Ben,
Postępowałem zgodnie z tym modułem przykładowym, ale za każdym razem wybrałem błąd przy pierwszym rozwijaniu: Ostrzeżenie: array_values ​​() oczekuje, że parametr 1 będzie tablicą, łańcuch podany w _field_filter_items () (wiersz 525 I: \ My Documents \ web \ xampp \ htdocs \ mysite \ modules \ field \ field.module). Korzystam z formularza wieloetapowego w połączeniu z rozwijaną listą zależną od ajax, którą napisałem w niestandardowym module nadpisywania .... Chociaż wartości zmieniają się dla drugiego dd na podstawie pierwszego. Pojawia się tylko ostrzeżenie, ale irytujące ... czy ktoś może mi pomóc usunąć to ostrzeżenie? dzięki!
stycznia 11
2 Ważne różnice między tym kodem a tym, co skończyło się na pracy w @Ben. Zauważ, że # suffix używa identyfikatora, a wywołanie zwrotne ajax zwraca element formularza, a nie cały formularz. Poza tym było to bardzo pomocne!
wolffer-east
11

Wielkie podziękowania dla jordojuice powyżej. Z jego pomocą udało mi się znaleźć rozwiązanie. Odniosłem się również do przykładu pod adresem http://public-action.org/content/drupal-7-form-api-dependent-lists-and-ajax-form-submission . W końcu użyłem kodu, który działał w module niestandardowym. Z jakiegoś powodu nie mogłem znaleźć żadnej z moich wartości w wartości $ form_state, ale byłem w stanie znaleźć je w $ postaci. W końcu, kiedy testowałem, otrzymywałem komunikat o błędzie, że Drupal wykrył nieprawidłowy wybór w menu rozwijanym. Obejrzałem to, komentując linię 1290 w form.inc:

form_error($elements, $t('An illegal choice has been detected. Please contact the site administrator.'));

Ostateczny kod, którego użyłem to:

<?php

function sappers_squadron_form_work_history_node_form_alter(&$form, &$form_state) {     
        //echo '<pre>';
        //print_r ($form);
        //echo '</pre>';

        $squadron_options = array();

        if(isset($form['field_wkhist_city']['und']['#default_value'][0])) {
            $city = $form['field_wkhist_city']['und']['#default_value'][0];
        }
        else {
            $city = 0;
        }

        $squadron_options = sappers_squadron_squadrons($city);

        $form['field_wkhist_city']['und']['#ajax'] = array(
            'event' => 'change',
            'wrapper' => 'squadron-wrapper',
            'callback' => 'sappers_squadron_ajax_callback',
            'method' => 'replace',
        );

        $form['field_squadron']['und']['#prefix'] = '<div id="squadron-wrapper">';
        $form['field_squadron']['und']['#suffix'] = '</div>';
        $form['field_squadron']['und']['#options'] = $squadron_options;
}


function sappers_squadron_ajax_callback($form, $form_state) {   
    $city = $form['field_wkhist_city']['und']['#value'];

    $form['field_squadron']['und']['#options'] = sappers_squadron_squadrons($city);

    return $form['field_squadron'];
}


function sappers_squadron_squadrons($city) {
    $nodes = array();

    $select = db_query("SELECT node.title AS node_title, node.nid AS nid FROM  {node} node INNER JOIN {taxonomy_index} taxonomy_index ON node.nid = taxonomy_index.nid WHERE (( (node.status = '1') AND (node.type IN  ('squadron')) AND (taxonomy_index.tid = $city) )) ORDER BY node_title ASC");

    $nodes[]="";

    foreach ($select as $node) {
            $nodes[$node->nid] = $node->node_title;
    }

    return $nodes;
}

?>
Ben
źródło
Dostaję Wykryto nielegalny wybór. Proszę skontaktować się z administratorem serwisu. błąd podczas próby wdrożenia powyżej. Możesz pomóc?
harshal
@harshal - Miałem ten sam problem i udało mi się go obejść, wdrażając rozwiązanie podane w mojej odpowiedzi, patrz powyżej (zmiana form.inc). To trochę hack, ale zadziałało dla mnie.
Ben
@harshal - Prawdopodobnie lepszym rozwiązaniem jest to podane przez Hackera poniżej.
Ben
1

wstaw wiersz kodu, tj.
$nodes[''] = '- None -'; po

 $nodes = array();

w sappers_squadron_squadrons function twoim, a to rozwiąże twój błąd

form_error($elements, $t('An illegal choice has been detected. Please contact the site administrator.'));

Haker
źródło
1

Użyj modułu ograniczenia opcji Pole referencyjne

Ten moduł pozwala ograniczać dostęp do opcji widżetów kilku typów przez wartości innych pól w bieżącym obiekcie.

Rakesh Nimje
źródło
Czy jest to alternatywa dla modułu pól warunkowych?
Umair,