Lista de seleção dinâmica no formulário (lista suspensa dependente)


28

Estou usando o Drupal sete. Desejo que as opções em uma lista de seleção dependam do valor escolhido em outra lista de seleção em um formulário. Tenho certeza de que isso já foi solicitado muitas vezes antes, mas estou tendo dificuldade em encontrar uma resposta clara sobre como fazer isso.

O formulário é para usuários inserirem um histórico de trabalho. Eles precisam selecionar um esquadrão que seja uma referência de nó ao tipo de campo do esquadrão, e isso está em uma lista suspensa. No entanto, o esquadrão depende de uma lista suspensa da cidade. Os usuários primeiro precisam selecionar uma cidade que, em seguida, filtrará as opções do esquadrão. No tipo de conteúdo do esquadrão, criei uma taxonomia para a cidade que é marcada para o esquadrão.

Ficaria muito grato por qualquer indicação da melhor maneira (mais simples?) De fazer isso, ou por quaisquer recursos on-line úteis que ajudariam.

Respostas:


27

Você pode usar o Ajax para fazer isso. O Drupal 7 agora tem um bom suporte ao Ajax. Na sua primeira lista de seleção (cidade), você precisará adicionar informações do Ajax. Em seguida, a segunda lista de seleção pode ser preenchida com base nas informações da primeira. Você também pode ocultar a segunda lista de seleção até que uma opção na primeira seja selecionada, e eu explicarei como fazer isso daqui a pouco. Primeiro, para configurar o formulário básico:

$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,
);

Esta é apenas a configuração básica dos elementos. Agora você precisará de uma maneira de determinar quais opções devem estar no esquadrão. Primeiro, você precisa identificar seu retorno de chamada do Ajax na lista de seleção 'cidade'. Na maioria dos casos, você pode simplesmente retornar o elemento que envolve o elemento ajax, neste caso $ form.

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

Agora, quando a lista de seleção 'cidade' mudar, ela reconstruirá a parte do esquadrão-invólucro. O valor da sua 'cidade' agora estará em $ form_state ['values']. Portanto, quando o formulário é reconstruído, precisamos determinar quais opções dar à lista de seleção com base no valor de 'cidade'.

// 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,
  );
}

6
Exemplos podem ser encontrados no módulo Exemplos ("Exemplos AJAX" → "Lista suspensa dependente"). Você também pode ver no módulo Hierarchical Select .
precisa saber é o seguinte

A propósito, como alternativa, você pode fazer isso de várias etapas, mas não achei que isso parecesse o que você estava procurando. Também ^ boa chamada! Os módulos de exemplos são ótimos para aprender esse tipo de coisa.
precisa saber é o seguinte

@jordojuice Muito obrigado pela sua resposta. Estou trabalhando nisso agora. No terceiro exemplo do código que você forneceu acima (iniciando // Obtenha o valor ...) em qual função eu coloco essa parte do código? Ele vai na função _ajax_callback? Obrigado
Ben

Eu segui o módulo de exemplo para isso, mas eu recebia um erro toda vez que selecionava um item no primeiro menu suspenso: Aviso: array_values ​​() espera que o parâmetro 1 seja array, string fornecida em _field_filter_items () (linha 525 de I: \ My Documents \ web \ xampp \ htdocs \ meusite \ módulos \ campo \ campo.modulo). Estou usando um formulário de várias etapas em conjunto com este menu suspenso dependente de ajax que escrevi em um módulo de substituição personalizado .... Embora os valores sejam alterados para o segundo dd com base no primeiro. É apenas um aviso aparecendo, mas irritante ... alguém pode me ajudar a remover esse aviso? obrigado!
jan

2 Diferenças importantes entre esse código e o que acabou funcionando no @Ben. Observe que o #suffix usa um ID e o retorno de chamada ajax retorna o elemento do formulário, não o formulário inteiro. Fora isso, isso foi super útil!
Wolffer-leste

11

Muito obrigado a jordojuice acima. Com a ajuda dele, consegui encontrar uma solução. Também me referi ao exemplo em http://public-action.org/content/drupal-7-form-api-dependent-lists-and-ajax-form-submission . Acabei usando o código abaixo, que funcionava em um módulo personalizado. Por alguma razão, não consegui encontrar nenhum dos meus valores nos valores $ form_state, mas consegui encontrá-los no formato $. Finalmente, quando testei, recebi uma mensagem de erro informando que Drupal havia detectado uma escolha ilegal no menu suspenso. Cheguei a esse ponto comentando a linha 1290 em form.inc:

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

O código final que usei foi:

<?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;
}

?>

Recebo uma opção ilegal detectada. Entre em contato com o administrador do site. erro quando tentei implementar acima. Você pode ajudar?
harshal

@harshal - I had the same problem and got round it by implementing the solution I give in my answer, please see above (altering form.inc). This is a bit of a hack but it worked for me.
Ben

@harshal - Provavelmente uma solução melhor é aquela fornecida por Hacker abaixo.
23716 Ben Ben

1

coloque a linha de código ou seja,
$nodes[''] = '- None -'; depois

 $nodes = array();

em ur sappers_squadron_squadrons function e isso resolverá seu erro

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



Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.