Lista de selección dinámica en el formulario (menú desplegable dependiente)


28

Estoy usando Drupal siete. Quiero hacer que las opciones en una lista de selección dependan del valor elegido en otra lista de selección en un formulario. Estoy seguro de que esto se ha preguntado muchas veces antes, pero estoy teniendo dificultades para encontrar una respuesta clara sobre cómo hacerlo.

El formulario es para que los usuarios ingresen un historial de trabajo. Necesitan seleccionar un escuadrón que sea una referencia de nodo para el tipo de campo del escuadrón, y esto está en una lista desplegable. Sin embargo, el escuadrón depende de una lista desplegable de la ciudad. Los usuarios primero deben seleccionar una ciudad que luego filtre las opciones para el escuadrón. En el tipo de contenido del escuadrón, creé una taxonomía para la ciudad que se etiqueta al escuadrón.

Estaría muy agradecido por cualquier sugerencia sobre la mejor manera (¿la más simple?) De hacer esto, o por cualquier recurso útil en línea que pueda ayudar.

Respuestas:


27

Puedes usar Ajax para lograr esto. Drupal 7 tiene buen soporte Ajax ahora. En su primera lista de selección (ciudad) deberá agregar información de Ajax. Luego, la segunda lista de selección se puede completar según la información de la primera. Incluso puede ocultar la segunda lista de selección hasta que se seleccione una opción en la primera, y explicaré cómo hacerlo en un momento. Primero, para configurar la forma básica:

$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 es solo la configuración básica de los elementos. Ahora necesitará una manera de determinar qué opciones deben ir en el escuadrón. Primero debe hacer que su devolución de llamada Ajax se identifique en la lista de selección 'ciudad'. En la mayoría de los casos, puede devolver el elemento que envuelve el elemento ajax, en este caso $ form.

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

Ahora, cuando la lista de selección 'ciudad' cambie, reconstruirá la parte de envoltura del escuadrón del formulario. Su valor de 'ciudad' ahora estará en $ form_state ['valores']. Entonces, cuando se reconstruye el formulario, necesitamos determinar qué opciones dar a la lista de selección en función del valor de 'ciudad'.

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

66
Se pueden encontrar ejemplos en el módulo Ejemplos ("Ejemplos AJAX" → "Menú desplegable dependiente"). También puede ver en el módulo Selección jerárquica .
kalabro

Por cierto, alternativamente, puedes hacer esto en una forma de varios pasos, pero no pensé que sonara como lo que estabas buscando. También ^ buena llamada! Los módulos de ejemplos son excelentes para aprender este tipo de cosas.
jordojuice

@jordojuice Muchas gracias por tu respuesta. Estoy trabajando en eso a hora. En el tercer ejemplo del código que da arriba (comenzando // Obtenga el valor ...) ¿en qué función pongo esta parte del código? ¿Va en la función _ajax_callback? Gracias
Ben

Seguí el módulo de ejemplo para esto, pero recibo un error cada vez que selecciono un elemento en el primer menú desplegable: Advertencia: array_values ​​() espera que el parámetro 1 sea matriz, cadena dada en _field_filter_items () (línea 525 de I: \ Mis documentos \ web \ xampp \ htdocs \ mysite \ modules \ field \ field.module). Estoy usando un formulario de varios pasos junto con este menú desplegable dependiente de ajax que escribí en un módulo de anulación personalizado ... Aunque los valores se cambian para el segundo dd en función del primero. Sin embargo, es solo una advertencia que aparece pero irritante ... ¿alguien puede ayudarme a eliminar esa advertencia? ¡Gracias!
Jan

2 Diferencias importantes entre este código y lo que terminó funcionando para @Ben. Tenga en cuenta que #suffix usa una identificación, y la devolución de llamada ajax devuelve el elemento de formulario, no el formulario completo. Aparte de eso, esto fue muy útil.
wolffer-east el

11

Muchas gracias a jordojuice arriba. Con su ayuda logré encontrar una solución. También me referí al ejemplo en http://public-action.org/content/drupal-7-form-api-dependent-lists-and-ajax-form-submission . Finalmente utilicé el siguiente código que funcionaba en un módulo personalizado. Por alguna razón, no pude encontrar ninguno de mis valores en los valores $ form_state, pero pude encontrarlos en $ form. Finalmente, cuando probé, recibí un mensaje de error de que Drupal había detectado una elección ilegal en el menú desplegable. Lo resolví comentando la línea 1290 en form.inc:

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

El código final que utilicé fue:

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

?>

Me aparece una opción ilegal detectada. Por favor contacte al administrador del sitio. error cuando intenté implementar arriba. ¿Puedes ayudar?
harshal

@harshal - Tuve el mismo problema y lo solucioné implementando la solución que proporcioné en mi respuesta, vea arriba (alterando form.inc). Esto es un truco pero funcionó para mí.
Ben

@harshal - Probablemente una mejor solución es la que da Hacker a continuación.
Ben

1

poner la línea de código, es decir,
$nodes[''] = '- None -'; después

 $nodes = array();

en tu sappers_squadron_squadrons function y eso resolverá tu error

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



Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.