Comment faire un formulaire obligatoire avec les états?

31

J'ai une liste déroulante qui affiche divers champs en fonction de ce qui est choisi et je sais que je peux parcourir la visibilité avec des états, mais lorsque j'essaie d'utiliser requis, la * span est affichée mais elle n'est pas réellement requise. Ce que je veux dire, c'est que même si c'est "obligatoire", je peux appuyer sur soumettre et ne pas recevoir de message d'erreur de drupal. Suis-je en train de faire quelque chose de mal ou est-ce actuellement cassé dans Drupal 7.8?

        $form['host_info'] = array(
        '#type' => 'select',
        '#title' => t("Host Connection"),
        '#options' => array(
          'SSH2' => t('SSH2'),
          'Web Service' => t('Web Service'),
        ),
        '#default_value' => t(variable_get('host_info', 'SSH2')),
        '#description' => t("Specify the connection information to the host"),
        '#required' => TRUE,
    );

    $form['ssh_host'] = array(
        '#type' => 'textfield',
        '#title' => t("Host Address"),
        '#description' => t("Host address of the SSH2 server"),
        '#default_value' => t(variable_get('ssh_host')),
        '#states' => array(
            'visible' => array(
                ':input[name=host_info]' => array('value' => t('SSH2')),
            ),
            'required' => array(
                ':input[name=host_info]' => array('value' => t('SSH2')),
            ),
        ),
    );

    $form['ssh_port'] = array(
        '#type' => 'textfield',
        '#title' => t("Port"),
        '#description' => t("Port number of the SSH2 server"),
        '#default_value' => t(variable_get('ssh_port')),
        '#states' => array(
            'visible' => array(
                ':input[name=host_info]' => array('value' => t('SSH2')),
            ),
            'required' => array(
                ':input[name=host_info]' => array('value' => t('Web Service')),
            ),
        ),
    );
Sathariel
la source
Vous manquez les guillemets doubles pour name. Ça doit l'être :input[name="host_info"].
leymannx

Réponses:

20

Vous devrez le valider vous-même dans une fonction de validation personnalisée.

Tout ce qui est configuré par #states se produit à 100% dans le navigateur, tout ce qu'il fait n'est pas visible pour Drupal lorsque le formulaire est soumis (par exemple, tous les champs de formulaire invisibles sont soumis et validés de la même manière s'il n'y avait pas de #states).

Berdir
la source
J'ai pensé que c'était le cas. Lorsque je cherchais comment faire cela, j'ai découvert l'attribut «requis» avec les états et j'ai pensé que cela fonctionnerait comme je le voulais sans travail supplémentaire.
Sathariel
11

Vous pouvez utiliser requis comme ceci:

'#states'=> [
  'required' => [
    ':input[name="abroad_because[somecheckbox]"]' => ['checked' => TRUE],
  ],
],
MuschPusch
la source
4
Oui - cela ajoutera l'indicateur requis à l'élément. Mais il n'y aura aucune validation côté client ou serveur impliquée.
AyeshK
Cela pourrait être un bug? Éléments requis buggy avec #states
colan
Mettre la clé requise dans le tableau #states semblait fonctionner pour moi, bien que ce soit le fait que j'avais une validation de champ de messagerie. Donc, je me demande si vous utilisez simplement le drupal par défaut #element_validate sur l'élément de formulaire, cela fonctionnera?
Alex Finnarn
8

Très similaire à la réponse de Felix Eve, ceci est un extrait de validation d'élément en ligne:

Vous appelez une fonction de validation d'élément l'élément requis:

$form['element'] = array(
....
  '#element_validate' => array(
     0 => 'my_module_states_require_validate',
   ),
)

Ensuite, la fonction de validation trouve le champ requis et vérifie s'il a la valeur de formulaire correcte qui révélerait le champ qui doit être requis.

function my_module_states_require_validate($element, $form_state) {
  $required_field_key = key($element['#states']['visible']);
  $required_field = explode('"', $required_field_key);
  if($form_state['values'][$required_field[1]] == $element['#states']['visible'][$required_field_key]['value']) {
    if($form_state['values'][$element['#name']] == '') {
      form_set_error($element['#name'], $element['#title'].' is required.');
    }
  }
}
Dominic Woodman
la source
1
Ceci est la meilleure solution à mon humble avis!
Alex Finnarn
3

Il existe une autre façon d'utiliser la fonction AFTER_BUILD pour le formulaire et de rendre ce champ facultatif. Voici un lien pour drupal 6.

Ajoutez ceci à votre code de formulaire

$form['#after_build'][] = 'custom_form_after_build';

Implémentez après la construction, testez votre condition de champ personnalisé

function custom_form_after_build($form, &$form_state) {
  if(isset($form_state['input']['custom_field'])) {
    $form['another_custom_field']['#required'] = FALSE;
    $form['another_custom_field']['#needs_validation'] = FALSE;
  }
 return $form;
}

Dans mon cas, #states ajoutait plusieurs * donc je dois l'éviter et j'ai utilisé jquery pour masquer et afficher la plage qui contient *

$('.another-custom-field').find('span').hide();  

Et

$('.another-custom-field').find('span').show();

Basé sur ma valeur custom_field.

atyagi
la source
3

Voici un guide détaillé sur les états # de Drupal 7 .

C'est le bit important:

/**
 * Form implementation.
 */
function module_form($form, $form_state) {
  $form['checkbox_1'] = [
    '#title' => t('Checkbox 1'),
    '#type' => 'checkbox',
  ];

  // If checkbox is checked then text input
  // is required (with a red star in title).
  $form['text_input_1'] = [
    '#title' => t('Text input 1'),
    '#type' => 'textfield',
    '#states' => [
      'required' => [
        'input[name="checkbox_1"]' => [
          'checked' => TRUE,
        ],
      ],
    ],
  ];

  $form['actions'] = [
    'submit' => [
      '#type' => 'submit',
      '#value' => t('Submit'),
    ],
  ];

  return $form;
}

/**
 * Form validate callback.
 */
function module_form_validate($form, $form_state) {
  // if checkbox is checked and text input is empty then show validation
  // fail message.
  if (!empty($form_state['values']['checkbox_1']) &&
    empty($form_state['values']['text_input_1'])
  ) {
    form_error($form['text_input_1'], t('@name field is required.', [
      '@name' => $form['text_input_1']['#title'],
    ]));
  }
}
Wim Mostrey
la source
2

Je viens d'être confronté au même problème, donc j'avais besoin de fournir une validation personnalisée, mais je voulais que cela soit contrôlé via le tableau #states, donc je n'ai pas eu à spécifier deux fois les mêmes règles.

Il fonctionne en extrayant le nom du champ du sélecteur jQuery (le sélecteur doit être au format :input[name="field_name"]ou il ne fonctionnera pas).

Le code ci-dessous n'est testé que dans le scénario spécifique dans lequel je l'utilisais, mais je pense qu'il peut s'avérer utile à quelqu'un d'autre.

function hook_form_validate($form, &$form_state) {

    // check for required field specified in the states array

    foreach($form as $key => $field) {

        if(is_array($field) && isset($field['#states']['required'])) {

            $required = false;
            $lang = $field['#language'];

            foreach($field['#states']['required'] as $cond_field_sel => $cond_vals) {

                // look for name= in the jquery selector - if that isn't there then give up (for now)
                preg_match('/name="(.*)"/', $cond_field_sel, $matches);

                if(isset($matches[1])) {

                    // remove language from field name
                    $cond_field_name = str_replace('[und]', '', $matches[1]);

                    // get value identifier (e.g. value, tid, target_id)
                    $value_ident = key($cond_vals);

                    // loop over the values of the conditional field
                    foreach($form_state['values'][$cond_field_name][$lang] as $cond_field_val) {

                        // check for a match
                        if($cond_vals[$value_ident] == $cond_field_val[$value_ident]) {
                            // now we know this field is required
                            $required = true;
                            break 2;
                        }

                    }

                }

            }

            if($required) {
                $field_name = $field[$lang]['#field_name'];
                $filled_in = false;
                foreach($form_state['values'][$field_name][$lang] as $item) {
                    if(array_pop($item)) {
                        $filled_in = true;
                    }
                }
                if(!$filled_in) {
                    form_set_error($field_name, t(':field is a required field', array(':field' => $field[$lang]['#title'])));
                }
            }

        }
    }

}
Felix Eve
la source
2

J'ai pu le faire de cette façon dans Drupal 8:

          '#states' => array(
            'required' => array(
              array(':input[name="host_info"]' => array('value' => 'SSH2')),
             ),
           ),

Ne mettez pas t ('SSH2'). cela mettra la traduction de celui-ci au lieu de la valeur de l'option qui est un SSH2 non traduit.

Je soupçonne que cela fonctionnerait aussi pour Drupal 7.

Volonté
la source
1
Dans drupal 7, comme indiqué dans les réponses donnant des solutions similaires, cela fournit les marquages ​​de champ requis, mais n'effectue en fait aucune validation. Drupal 8 valide-t-il réellement les champs marqués comme requis en utilisant #states?
UltraBob
0

J'ai des champs de formulaire imbriqués et une case à cocher, donc je devais travailler un peu sur la réponse de Dominic Woodman. Au cas où un autre organisme rencontrerait le même problème:

function my_module_states_require_validate($element, $form_state) {
  $required_field_key = key($element['#states']['visible']);
  $required_field = explode('"', $required_field_key);
  $keys = explode('[', $required_field[1]);
  $keys = str_replace(']', '', $keys);
  $tmp = $form_state['values'];
  foreach ($keys as $key => $value) {
    $tmp = $tmp[$value];
  }
  if($tmp == $element['#states']['visible'][$required_field_key]['checked']) {
    $keys2 = explode('[', $element['#name']);
    $keys2 = str_replace(']', '', $keys2);
    $tmp2 = $form_state['values'];
    foreach ($keys2 as $key => $value) {
      $tmp2 = $tmp2[$value];
    }
    if($tmp2 == '') {
      form_set_error($element['#name'], $element['#title']. t(' is required.'));
    }
  }
}
Koli
la source