Wie erstelle ich ein Formular mit Staaten erforderlich?

31

Ich habe eine Dropdown-Liste, in der verschiedene Felder angezeigt werden, je nachdem, was ausgewählt wurde, und ich weiß, dass ich die Sichtbarkeit mit Status googeln kann. Wenn ich jedoch versuche, "Erforderlich" zu verwenden, wird "* span" angezeigt, dies ist jedoch nicht erforderlich. Was ich damit meine ist, dass ich, obwohl es "erforderlich" ist, auf "Senden" klicken und keine Fehlermeldung von Drupal erhalten kann. Mache ich etwas falsch oder ist das derzeit in Drupal 7.8 kaputt?

        $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
quelle
Ihnen fehlen die doppelten Anführungszeichen für name. Es muss sein :input[name="host_info"].
Leymannx

Antworten:

20

Sie müssen dies selbst in einer benutzerdefinierten Validierungsfunktion validieren.

Alles, was von #states konfiguriert wurde, geschieht zu 100% im Browser. Alles, was es tut, ist für Drupal nicht sichtbar, wenn das Formular gesendet wird.

Berdir
quelle
Ich nahm an, dass das der Fall war. Als ich nachforschte, wie das geht, entdeckte ich das Attribut 'required' mit states und dachte, es würde so funktionieren, wie ich es brauchte, ohne zusätzliche Arbeit.
Sathariel
11

Sie können erforderlich wie folgt verwenden:

'#states'=> [
  'required' => [
    ':input[name="abroad_because[somecheckbox]"]' => ['checked' => TRUE],
  ],
],
MuschPusch
quelle
4
Ja - dies fügt dem Element den erforderlichen Indikator hinzu. Es ist jedoch keine clientseitige oder serverseitige Validierung erforderlich.
AyeshK
Könnte ein Fehler sein? Erforderliche Elemente Buggy mit #States
Colan
Das Einfügen des erforderlichen Schlüssels in das Array #states schien für mich zu funktionieren, obwohl ich eine E-Mail-Feldvalidierung hatte. Ich frage mich also, ob Sie nur den Standard-Drupal #element_validate für das Formularelement verwenden, das funktionieren wird.
Alex Finnarn
8

Ganz ähnlich wie die Antwort von Felix Eve ist dies nur ein Ausschnitt für die Inline-Elementvalidierung:

Sie nennen eine Elementvalidierungsfunktion das gewünschte Element:

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

Dann findet die Validierungsfunktion das erforderliche Feld und prüft, ob es den korrekten Formularwert hat, der das Feld enthüllt, das benötigt wird.

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
quelle
1
Dies ist die beste Lösung, IMHO!
Alex Finnarn
3

Es gibt eine andere Möglichkeit, die AFTER_BUILD-Funktion für das Formular zu verwenden und dieses Feld optional zu machen. Hier ist ein Link für Drupal 6.

Fügen Sie dies Ihrem Formularcode hinzu

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

Testen Sie nach der Implementierung Ihre benutzerdefinierte Feldbedingung

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

In meinem Fall hat #states mehrere * hinzugefügt, daher muss ich dies vermeiden und habe jquery verwendet, um den Bereich, der * enthält, auszublenden und anzuzeigen.

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

Und

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

Basierend auf meinem custom_field-Wert.

atyagi
quelle
3

Hier ist eine detaillierte Anleitung zu Drupal 7 von #states .

Das ist das Wichtige:

/**
 * 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
quelle
2

Ich war gerade mit demselben Problem konfrontiert, das für die Bereitstellung einer benutzerdefinierten Validierung erforderlich war. Ich wollte jedoch, dass dies über das Array #states gesteuert wird, damit ich nicht zweimal dieselben Regeln angeben musste.

Es funktioniert durch Extrahieren des Feldnamens aus dem jQuery-Selektor (der Selektor muss im Format vorliegen, sonst :input[name="field_name"]funktioniert es nicht).

Der folgende Code wird nur in dem speziellen Szenario getestet, in dem ich ihn verwendet habe, obwohl er sich für andere als nützlich erweisen könnte.

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
quelle
2

Ich konnte es in Drupal 8 so machen:

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

Setzen Sie nicht t ('SSH2'). Dadurch wird die Übersetzung dorthin verschoben, anstatt des Werts der Option, bei der es sich um eine nicht übersetzte SSH2 handelt.

Ich vermute, dass dies auch für Drupal 7 funktionieren würde.

Wille
quelle
1
In Drupal 7 werden, wie auf Antworten mit ähnlichen Lösungen hingewiesen, die erforderlichen Feldmarkierungen bereitgestellt, es wird jedoch keine eigentliche Validierung durchgeführt. Überprüft Drupal 8 tatsächlich Felder, die als erforderliche Verwendungen #states markiert sind?
UltraBob
0

Ich habe Formularfelder und ein Kontrollkästchen verschachtelt, also musste ich ein wenig an Dominic Woodmans Antwort arbeiten. Für den Fall, dass eine andere Stelle auf dasselbe Problem stößt:

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
quelle