it-swarm.com.de

Wie rendere ich eine Senden-Schaltfläche, damit sie anfänglich deaktiviert und von JavaScript aktiviert wird?

Wir haben ein Formular, das eine React JS-Frontend-Komponente enthält. Die Komponente sammelt einige erforderliche Informationen, die die React -Komponente dann an das Backend liefert, indem sie eine versteckte Komponente ausfüllt Formularfeld.

Um sicherzustellen, dass ein Benutzer die Eingabe der erforderlichen Daten über die Komponente nicht umgehen kann, müssen die folgenden Anforderungen erfüllt sein:

  • Bevor die Komponente React React) geladen wird, muss die Schaltfläche "Submit" deaktiviert werden. Dadurch wird sichergestellt, dass ein Benutzer das Formular nicht einfach durch Deaktivieren von JS oder Klicken auf die Schaltfläche senden kann, bevor die Seite vollständig geladen ist .
  • Nach dem Laden der Komponente React Component) muss die Schaltfläche "Submit" deaktiviert werden, sobald die erforderlichen Werte gelöscht werden.
  • Sobald die erforderlichen Werte eingegeben wurden, sollte die Schaltfläche "Senden" aktiviert sein.
  • Es darf nicht möglich sein, das Formular zu senden, wenn der versteckte Wert leer ist.

Ich habe versucht, das Formular folgendermaßen zu rendern:

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = [];

    $form['selected_values'] = [
      '#type' => 'hidden',
    ];

    $form['actions'] = [
      '#type'   => 'actions',
      '#weight' => 100,
    ];

    $form['actions']['submit'] = [
      '#type'         => 'submit',
      '#value'        => $this->t('Submit'),
      '#button_type'  => 'primary',
      '#disabled'     => TRUE, // Controlled by JS on the frontend
    ];

    return $form;
  }

Und dann habe ich in JavaScript einen onValueChange() - Ereignisrückruf, der so aussieht:

function onValueChange(value) {
  if (value.trim() === '') {
    $(submitButton).prop('disabled', true);
  }
  else {
    $(submitButton)
      .prop('disabled', false)
      .removeClass('is-disabled');
  }
}

Ich habe auch versucht:

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = [];

    $selected_values = form_state->getValue('selected_values');

    $form['selected_values'] = [
      '#type' => 'hidden',
    ];

    $form['actions'] = [
      '#type'   => 'actions',
      '#weight' => 100,
    ];

    $form['actions']['submit'] = [
      '#type'         => 'submit',
      '#value'        => $this->t('Submit'),
      '#button_type'  => 'primary',
      '#disabled'     => !empty($selected_values),
    ];

    return $form;
  }

Beide Ansätze weisen dasselbe Problem auf: Wenn Sie auf "Senden" klicken, wird das Formular nicht gesendet. es scheint nur die Form neu aufzubauen. Beim zweiten Ansatz sieht es so aus, als ob die eingehenden ausgewählten Werte beim Rendern des Formulars immer leer sind. Sie werden erst auf den Formularstatus angewendet, wenn nach das Formular erstellt wurde.

Wie können wir sicherstellen, dass die Schaltfläche "Senden" deaktiviert startet und die erforderlichen Werte benötigt werden?

2
GuyPaddock

Verwenden von #disabled auf der Schaltfläche "Senden" ist die falsche Lösung, da es der Drupal Formular-API mitteilt, dass die Schaltfläche keine Eingabe erwartet. Mit anderen Worten, es verursacht Drupal = so zu tun, als ob die Schaltfläche überhaupt nicht vorhanden wäre. Daher hat das Klicken auf die Schaltfläche "Senden" keine Auswirkung. Dies alles ist aus Sicherheitsgründen sinnvoll, da Sie normalerweise nicht möchten, dass geschickte Benutzer die Backend-Logik nur mithilfe von Entwicklertools deaktivieren Erzwingen, dass ein deaktiviertes oder schreibgeschütztes Formularelement aktiviert wird.

Stattdessen gibt es zwei Lösungen:

  1. Rendern Sie die Schaltfläche über HTML-Attribute als deaktiviert, sodass die Schaltfläche nur im Browser deaktiviert ist, aber weiterhin als aktive Schaltfläche im Backend betrachtet wird.
  2. Markieren Sie das versteckte Feld als '#required' => TRUE, so dass es nicht möglich ist, das Formular zu umgehen, selbst wenn der Benutzer mit Dev Tools vertraut ist.

So sieht das in der Praxis aus:

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = [];

    $form['selected_values'] = [
      // Though this field is hidden, it's required. So, the title is still
      // shown if/when the field is ever NULL during submission.
      '#title'    => $this->t('File selection'),
      '#type'     => 'hidden',
      '#required' => TRUE,
    ];

    $form['actions'] = [
      '#type'   => 'actions',
      '#weight' => 100,
    ];

    $form['actions']['submit'] = [
      '#type'         => 'submit',
      '#value'        => $this->t('Submit'),
      '#button_type'  => 'primary',
      '#attributes' => [
        // This button is programmatically enabled/disabled via JS on the
        // frontend.
        'disabled' => 'disabled',
    ];

    return $form;
  }

Die Frontend-Logik zum Aktivieren der Schaltfläche bleibt unverändert. Der Unterschied besteht darin, dass die Schaltfläche nur im gerenderten HTML-Code deaktiviert ist und nicht im Backend-Formular. Wenn ein geschickter Benutzer die Schaltfläche aktiviert, indem er das Attribut disabled im HTML-DOM-Element entfernt, wird nur ein Validierungsfehler angezeigt, der besagt:

Das Dateiauswahlfeld ist erforderlich.

Unabhängig davon, warum der zweite Ansatz die Schaltfläche "Senden" basierend auf den eingehenden Werten nicht aktivieren/deaktivieren konnte, liegt dies daran, dass Drupal erstellt das Formular zuerst, bevor die eingehenden Werte verarbeitet werden, damit es weiß Welche Formularelemente müssen aufgerufen werden, um die Eingabe zu verarbeiten. Zum Zeitpunkt des Aufrufs des Formularerstellers sind also noch keine Werte für den Formularstatus vorhanden. Hypothetisch ist es möglicherweise möglich, die Roheingabe über $form_state->getUserInput() abzurufen und dann zu steuern, ob die Schaltfläche basierend darauf aktiviert werden soll oder nicht; dieser Ansatz kann jedoch Auswirkungen auf die Sicherheit haben.

2
GuyPaddock