Liste de sélection dynamique dans le formulaire (liste déroulante dépendante)

28

J'utilise Drupal sept. Je veux que les options d'une liste de sélection dépendent de la valeur choisie dans une autre liste de sélection d'un formulaire. Je suis sûr que cela a été demandé à plusieurs reprises auparavant, mais j'ai du mal à trouver une réponse claire sur la façon de procéder.

Le formulaire permet aux utilisateurs d'entrer un historique de travail. Ils doivent sélectionner un escadron qui est une référence de nœud au type de champ d'escadron, et cela se trouve dans une liste déroulante. Cependant, l'escadron dépend d'une liste déroulante des villes. Les utilisateurs doivent d'abord sélectionner une ville qui filtrera ensuite les options de l'escadron. Dans le type de contenu de l'escadron, j'ai créé une taxonomie pour la ville qui est étiquetée pour l'escadron.

Je serais très reconnaissant à tous les conseils sur la meilleure façon (la plus simple?) De procéder, ou à toute ressource utile en ligne qui pourrait aider.

Ben
la source

Réponses:

27

Vous pouvez utiliser Ajax pour cela. Drupal 7 a maintenant un bon support Ajax. Sur votre première liste de sélection (ville), vous devrez ajouter des informations Ajax. Ensuite, la deuxième liste de sélection peut être remplie en fonction des informations de la première. Vous pouvez également masquer la deuxième liste de sélection jusqu'à ce qu'une option de la première soit sélectionnée, et je vais vous expliquer comment le faire dans un instant. Tout d'abord, pour configurer le formulaire de base:

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

Ce n'est que la configuration de base des éléments. Maintenant, vous aurez besoin d'un moyen de déterminer quelles options devraient aller dans l'escadron. Vous devez d'abord faire votre rappel Ajax identifié dans la liste de sélection «ville». Dans la plupart des cas, vous pouvez simplement renvoyer l'élément qui enveloppe l'élément ajax, dans ce cas $ form.

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

Désormais, lorsque la liste de sélection «ville» change, elle reconstruit la partie enveloppe de l'escadron du formulaire. Votre valeur 'city' sera désormais dans $ form_state ['values']. Ainsi, lorsque le formulaire est reconstruit, nous devons déterminer les options à donner à la liste de sélection en fonction de la valeur de «ville».

// 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
la source
6
Des exemples peuvent être trouvés dans le module Exemples ("Exemples AJAX" → "Liste déroulante dépendante"). Vous pouvez également voir au module de sélection hiérarchique .
kalabro
Soit dit en passant, vous pouvez également le faire sous une forme en plusieurs étapes, mais je ne pensais pas que cela ressemblait à ce que vous cherchiez. Aussi ^ bon appel! Les exemples de modules sont parfaits pour apprendre ce genre de choses.
jordojuice
@jordojuice Merci beaucoup pour votre réponse. J'y travaille maintenant. Dans le troisième exemple du code que vous donnez ci-dessus (début // Obtenir la valeur ...) dans quelle fonction dois-je mettre cette partie du code? Va-t-il dans la fonction _ajax_callback? Merci
Ben
J'ai suivi l'exemple du module pour cela, mais j'ai une erreur à chaque fois que je sélectionne un élément dans le premier menu déroulant: Avertissement: array_values ​​() s'attend à ce que le paramètre 1 soit un tableau, chaîne donnée dans _field_filter_items () (ligne 525 de I: \ Mes documents \ web \ xampp \ htdocs \ mysite \ modules \ field \ field.module). J'utilise un formulaire en plusieurs étapes en conjonction avec cette liste déroulante dépendante ajax que j'ai écrite dans un module de remplacement personnalisé .... Bien que les valeurs soient modifiées pour le deuxième dd en fonction du premier. C'est juste un avertissement qui apparaît mais irritant ... quelqu'un peut-il m'aider à supprimer cet avertissement? Merci!
janvier
2 Différences importantes entre ce code et ce qui a fini par fonctionner pour @Ben. Notez que le #suffix utilise un identifiant et le rappel ajax renvoie l'élément de formulaire, pas le formulaire entier. A part ça, c'était super utile!
wolffer-east,
11

Un grand merci à jordojuice ci-dessus. Avec son aide, j'ai réussi à trouver une solution. J'ai également fait référence à l'exemple à http://public-action.org/content/drupal-7-form-api-dependent-lists-and-ajax-form-submission . J'ai finalement utilisé le code ci-dessous qui fonctionnait dans un module personnalisé. Pour une raison quelconque, je n'ai trouvé aucune de mes valeurs dans les valeurs $ form_state, mais j'ai pu les trouver sous $ form. Enfin, lorsque j'ai testé, je recevais un message d'erreur indiquant que Drupal avait détecté un choix illégal dans la liste déroulante. J'ai contourné cela en commentant la ligne 1290 dans form.inc:

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

Le code final que j'ai utilisé était:

<?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
la source
J'obtiens un choix illégal détecté. Veuillez contacter l'administrateur du site. erreur lorsque j'ai essayé de mettre en œuvre ci-dessus. Peux-tu aider?
harshal
@harshal - J'ai eu le même problème et je l'ai contourné en implémentant la solution que je donne dans ma réponse, voir ci-dessus (en modifiant form.inc). C'est un peu un hack mais ça a marché pour moi.
Ben
@harshal - Probablement une meilleure solution est celle donnée par Hacker ci-dessous.
Ben
1

mettre la ligne de code c'est
$nodes[''] = '- None -'; à dire après

 $nodes = array();

en ur sappers_squadron_squadrons function et cela résoudra votre erreur

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

Pirate
la source
1

La cause première de "Un choix illégal a été détecté. Veuillez contacter l'administrateur du site." est que la chaîne vide avec la valeur 0 ajoutée par $nodes[]="";n'est pas valide pour le champ field_squadron.

Voir Advance PHP Programming and Development , mais gardez à l'esprit que le DANGEROUS_SKIP_CHECK et les drapeaux validés sont déconseillés dans D7 .

Après avoir supprimé cette ligne, l'erreur a disparu.

Siripong
la source
1

Utiliser le module de limite d'option Champ de référence

Ce module permet aux champs de référence de plusieurs types de voir les options disponibles de leurs widgets limitées par les valeurs des autres champs de l'entité actuelle.

Rakesh Nimje
la source
Est-ce une alternative au module des champs conditionnels?
Umair