Come ricostruire il modulo dopo la chiamata AJAX


12

Sto tentando di consentire all'utente di scegliere dinamicamente un numero di campi in base a una casella a discesa utilizzando una chiamata Ajax, ma non riesco a ottenere la chiamata Ajax per ricostruire il modulo in seguito.

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

Il numero di campi di testo si basa sulla variabile form_state 'numero'. Il callback columnCallback modifica la variabile form_state in 10 e viene attivato quando viene modificato il campo del modulo 'columnNum'. Tuttavia, il modulo non viene ricostruito con il nuovo numero di campi anche se $ form_state-> setRebuild (); è chiamato. C'è un modo per ottenere il modulo da ricostruire dopo una chiamata Ajax?

NOTA: ho già provato tecniche come la sostituzione o l'aggiunta di elementi del modulo all'interno della chiamata ajax effettiva, ma quando ciò accade, nessuno degli input nei campi sostituiti viene passato a $ form_state.

AGGIORNAMENTO: Dopo aver tentato la soluzione di 4k4 ricevo un errore

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).

La convinzione è che l'errore si verifica perché $ form ['colonna'] sta restituendo null nonostante sia stato creato come contenitore nella funzione blockForm. Ho provato a chiamare il callback in altri modi come

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

e

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

Ma ricevo lo stesso errore. Curiosamente, quando cambio il callback per restituire l'intero $ form anziché solo $ form ['colonna'] ripete il modulo (una copia del modulo appare sotto il modulo corrente) e ancora senza il numero corretto di colonne.


Potrebbe essere un refuso ma un doppio controllo, sei consapevole che in columnCallback il primo argomento è un refuso (nessuno spazio tra array e & $ form)?
Kevin,

Risposte:


4

Il primo problema è gestire il valore per il numero di colonna. Al primo build ottenerlo dalla configurazione, su una ricostruzione ottenerlo dall'input dell'utente e inserirlo $columnNum.

Il secondo è decidere quale parte del modulo cambia in AJAX e inserirla in un contenitore div con l'id 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;
    }

Nel callback abbiamo solo bisogno di restituire il wrapper Ajax.

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

Drupal ricostruisce il modulo su ogni richiesta Ajax e lo inserisce nel parametro $formdel callback. Non avrebbe senso provare a ricostruirlo di nuovo.


1
Ricevo un errore dopo aver chiamato la richiesta Ajax. "Codice risultato HTTP: 200" Testo stato: OK Testo risposta:
Matt

1
Le cose di prova che ho eseguito un dado (print_r ($ form_state-> getValues ​​())); e mostrava correttamente il valore columnNum corretto. In caso contrario, errori.
Matt,

1
Ho messo le modifiche nel tuo codice per dimostrazione. Non è possibile eseguire il debug senza messaggi di errore con numeri di riga.
4k4,

2
Hai rimosso l'errore di sintassi dal commento di @ Kevin? Ci sono errori php nel registro errori? Dovrebbero essercene molte quando si testano nuovi codici come questo.
4k4,

2
Ha rintracciato l'errore, significa che return $form['column']è null, perché il valore restituito viene deselezionato renderResponse(). Potrebbe essere ancora un problema con l'elenco dei parametri del callback, perché inseriamo almeno un contenitore nella chiave del modulo e questo impedirebbe questo errore.
4k4,

2

Immagino che manchi il wrappertuo metodo '#ajax'(accanto a callback) che consiste idnell'attributo HTML dell'area in cui dovrebbe essere posizionato il contenuto restituito dal callback. Vedi: API Ajax . Quindi devi assicurarti che tale contenitore idesista.

Esempio di codice (semplificato):

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

Per un esempio di codice completo, vedi: Come aggiungere più opzioni per i tipi di radio usa Ajax in Drupal 8 .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.