So erstellen Sie das Formular nach einem AJAX-Aufruf neu

12

Ich versuche, dem Benutzer zu ermöglichen, mithilfe eines Ajax-Aufrufs dynamisch eine Anzahl von Feldern basierend auf einem Dropdown-Feld auszuwählen, aber ich kann den Ajax-Aufruf scheinbar nicht dazu bringen, das Formular anschließend neu zu erstellen.

<?php
class AJAXexample extends BlockBase {
    public function blockForm($form, FormStateInterface $form_state) {
        if (empty($form_state->getValue('number'))) {
            $form_state->setValue('number', 3);
        } 
        $form['columnNum'] = [
            '#title'   => t('Number of Columns'),
            '#type'    => 'select',
            '#options' => [
                1         => '1',
                2         => '2',
                3         => '3',
                4         => '4',
            ],
            '#default_value' => $this->configuration['columnNum'],
            '#empty_option'  => t('-select-'),
            '#ajax'          => [
                'callback'      => [$this, 'columnCallback'],
            ],
        ];
        for ($i = 0; $i < $form_state->getValue('number'); $i += 1) {
            $form['column'][$i] = [
                $i => [
                    '#type'       => 'details',
                    '#title'      => t('Column '.$numTitle),
                    '#open'       => FALSE,
                    'columnTitle' => [
                        '#type'      => 'textfield',
                        '#title'     => t('Column Title'),
                        '#value'     => $config[0]['columnTitle'],
                    ],  
                ],
            ];  
        return $form;
    }

    public function columnCallback(array &$form, FormStateInterface $form_state) {
        $form_state->setValue('number', 10);
        $form_state->setRebuild(true);
        return $form;
    }
}

Die Anzahl der Textfelder basiert auf der form_state-Variablen 'number'. Der Rückruf columnCallback ändert die Variable form_state in 10 und wird ausgelöst, wenn das Formularfeld 'columnNum' geändert wird. Das Formular wird jedoch nicht mit der neuen Anzahl von Feldern neu erstellt, obwohl $ form_state-> setRebuild (); wird genannt. Gibt es eine Möglichkeit, das Formular nach einem Ajax-Aufruf wiederherzustellen?

ANMERKUNG: Ich habe bereits Techniken ausprobiert, wie das Ersetzen oder Anhängen der Elemente des Formulars innerhalb des eigentlichen Ajax-Aufrufs, aber wenn dies geschieht, wird keine Eingabe in die ersetzten Felder an $ form_state übergeben.

UPDATE: Nach dem Versuch, 4k4 zu lösen, erhalte ich eine Fehlermeldung

Recoverable fatal error: Argument 1 passed to Drupal\Core\Render\MainContent\AjaxRenderer::renderResponse() must be of the type array, null given, called in /Library/WebServer/Documents/aaep/web/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php on line 89 and defined in Drupal\Core\Render\MainContent\AjaxRenderer->renderResponse() (line 45 of /Library/WebServer/Documents/aaep/web/core/lib/Drupal/Core/Render/MainContent/AjaxRenderer.php).

Die Annahme ist, dass der Fehler auftritt, weil $ form ['column'] null zurückgibt, obwohl es in der blockForm-Funktion als Container erstellt wurde. Ich habe versucht, den Rückruf auf andere Weise wie

'#ajax' => [
    'callback' => '::columnCallback',
]

und

'#ajax' => [
    'callback' => [$this, '\Drupal\my_examples\Plugin\Block\AJAXexample::columnCallback'],
]

Aber ich erhalte den gleichen Fehler. Wenn ich den Rückruf ändere, um das gesamte $ form anstelle von nur $ form ['column'] zurückzugeben, wird das Formular seltsamerweise wiederholt (eine Kopie des Formulars wird unter dem aktuellen Formular angezeigt) und immer noch ohne die richtige Anzahl von Spalten.

Matt
quelle
Könnte ein Tippfehler, aber eine doppelte Überprüfung sein. Ist Ihnen bewusst, dass das erste Argument in columnCallback ein Tippfehler ist (kein Leerzeichen zwischen Array und & $ form)?
Kevin

Antworten:

4

Das erste Problem besteht darin, den Wert für die Spaltennummer zu behandeln. Beim ersten Build wird es aus der Konfiguration abgerufen, beim erneuten Build wird es aus der Benutzereingabe abgerufen und abgelegt $columnNum.

Die zweite besteht darin, zu entscheiden, welcher Teil des Formulars in AJAX geändert wird, und dies in einen div-Container mit der ID zu legen columns-wrapper.

class AJAXexample extends BlockBase {
    public function blockForm($form, FormStateInterface $form_state) {
        $columnNum = empty($form_state->getValue('columnNum')) ? $this->configuration['columnNum'] : $form_state->getValue('columnNum');
        $form['columnNum'] = [
            '#title'   => t('Number of Columns'),
            '#type'    => 'select',
            '#options' => [
                1         => '1',
                2         => '2',
                3         => '3',
                4         => '4',
            ],
            '#default_value' => $this->configuration['columnNum'],
            '#empty_option'  => t('-select-'),
            '#ajax'          => [
                'callback'      => [$this, 'columnCallback'],
                'wrapper'       => 'columns-wrapper', 
            ],
        ];
        $form['column'] = [
            '#type' => 'container',
            '#attributes' => ['id' => 'columns-wrapper'],
        ];
        for ($i = 0; $i < $columnNum; $i += 1) {
            $form['column'][$i] = [
                $i => [
                    '#type'       => 'details',
                    '#title'      => t('Column '.$numTitle),
                    '#open'       => FALSE,
                    'columnTitle' => [
                        '#type'      => 'textfield',
                        '#title'     => t('Column Title'),
                        '#value'     => $config[0]['columnTitle'],
                    ],  
                ],
            ];  
        return $form;
    }

Im Rückruf müssen wir nur den Ajax-Wrapper zurückgeben.

public function columnCallback(array&$form, FormStateInterface $form_state) {
    return $form['column'];
}

Drupal erstellt das Formular bei jeder Ajax-Anfrage neu und fügt es in den Parameter $formdes Rückrufs ein. Es würde keinen Sinn machen, es erneut aufzubauen.

4k4
quelle
1
Ich erhalte eine Fehlermeldung, nachdem die Ajax-Anfrage aufgerufen wurde. 'HTTP-Ergebniscode: 200' StatusText: OK ResponseText:
Matt
1
Die Testsachen, die ich durchgeführt habe, sind Würfel (print_r ($ form_state-> getValues ​​()); und es wurde der richtige columnNum-Wert korrekt angezeigt. Sonst kommt es nur zu Fehlern.
Matt
1
Ich habe die Änderungen zu Demonstrationszwecken in Ihren Code eingefügt. Kann beim Debuggen ohne Fehlermeldungen mit Zeilennummern nicht helfen.
4. 4.
2
Haben Sie den Syntaxfehler aus @ Kevins Kommentar entfernt? Gibt es PHP-Fehler im Fehlerprotokoll? Es sollte eine Menge geben, wenn Sie neuen Code wie diesen testen.
4. 4.
2
Verfolgt den Fehler, bedeutet dies return $form['column'], dass er null ist, da der Rückgabewert deaktiviert wird renderResponse(). Könnte immer noch ein Problem mit der Parameterliste des Rückrufs sein, da wir mindestens einen Container in diesen Formularschlüssel setzen und dies diesen Fehler verhindern würde.
4. 4.
2

Vermutlich fehlt Ihnen wrapperin Ihrem '#ajax'(neben callback) die Methode , die aus dem HTML- idAttribut des Bereichs besteht, in dem der vom Rückruf zurückgegebene Inhalt platziert werden soll. Siehe: Ajax API . Dann müssen Sie sicherstellen, dass ein solcher Container idexistiert.

Codebeispiel (vereinfacht):

public function blockForm($form, FormStateInterface $form_state) {
    $form['wrapper'] = array(
        '#type' => 'container',
        '#attributes' => array('id' => 'data-wrapper'),
        );
    $form['wrapper']['columnNum'] = [
        '#title'   => t('Number of Columns'),
        '#type'    => 'select',
        '#options' => [1 => '1', 2 => '2'],
        '#default_value' => $this->configuration['columnNum'],
        '#ajax'          => [
            'callback'   => '::columnCallback',
            'wrapper'    => 'data-wrapper',
        ],
    ];
}
public function columnCallback(array &$form, FormStateInterface $form_state) {
    return $form['wrapper'];
}

Ein vollständiges Codebeispiel finden Sie unter: So fügen Sie weitere Optionen für Typradios hinzu Verwenden Sie Ajax in Drupal 8 .

Kenorb
quelle