Como reconstruir o formulário após a chamada AJAX

12

Estou tentando permitir que o usuário escolha dinamicamente vários campos com base em uma caixa suspensa usando uma chamada ajax, mas não consigo receber a chamada ajax para reconstruir o formulário posteriormente.

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

O número de campos de texto é baseado na variável form_state 'number'. O retorno de chamada columnCallback altera a variável form_state para 10 e é acionado quando o campo de formulário 'columnNum' é alterado. No entanto, o formulário não é reconstruído com o novo número de campos, apesar de $ form_state-> setRebuild (); é chamado. Existe uma maneira de obter o formulário para reconstruir após uma chamada de ajax?

NOTA: Eu já tentei técnicas como substituir ou anexar os itens do formulário dentro da chamada ajax real, mas quando isso acontece, nenhuma das entradas nos campos substituídos é passada para $ form_state.

ATUALIZAÇÃO: Depois de tentar a solução do 4k4, recebo um erro

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

A crença é que o erro ocorre porque $ form ['column'] está retornando nulo, apesar de ter sido criado como um contêiner na função blockForm. Tentei ligar para o retorno de outras maneiras, como

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

e

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

Mas eu recebo o mesmo erro. Curiosamente, quando altero o retorno de chamada para retornar todo o formulário $ em vez de apenas $ form ['column'], ele repete o formulário (uma cópia do formulário aparece abaixo do formulário atual) e ainda sem o número adequado de colunas.

Matt
fonte
Pode ser um erro de digitação, mas verifique duas vezes, você sabe que em columnCallback o primeiro argumento é um erro de digitação (sem espaço entre a matriz e o formulário $)?
Kevin

Respostas:

4

O primeiro problema é manipular o valor do número da coluna. Na primeira compilação, obtenha-a da configuração, em uma reconstrução, obtenha-a a partir da entrada do usuário e insira-a $columnNum.

O segundo é decidir qual parte do formulário muda no AJAX e colocá-lo em um contêiner div com o 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;
    }

No retorno de chamada, precisamos apenas retornar o wrapper ajax.

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

Drupal reconstrói o formulário em cada solicitação de ajax e o coloca no parâmetro $formdo retorno de chamada. Não faria sentido tentar reconstruí-lo novamente.

4k4
fonte
1
Eu recebo um erro depois que a solicitação ajax é chamada. 'HTTP Result Code: 200' StatusText: OK ResponseText:
Matt
1
O teste executou um dado (print_r ($ form_state-> getValues ​​())); e exibiu corretamente o valor columnNum adequado. Apenas erros fora.
Matt
1
Eu coloquei as alterações no seu código para demonstração. Não é possível ajudar na depuração sem mensagens de erro com números de linha.
4k4 15/08/16
2
Você removeu o erro de sintaxe do comentário de @ Kevin? Existem erros de php no log de erros? Deve haver muito ao testar um novo código como este.
4k4 15/08/16
2
Rastreado o erro, isso significa que return $form['column']é nulo, porque o valor de retorno é desmarcado renderResponse(). Ainda pode haver um problema com a lista de parâmetros do retorno de chamada, porque colocamos pelo menos um contêiner nessa chave de formulário e isso evitaria esse erro.
4k4 15/08/16
2

Acho que você está perdendo o wrappermétodo no '#ajax'(ao lado de callback) que consiste no idatributo HTML da área onde o conteúdo retornado pelo retorno de chamada deve ser colocado. Consulte: API do Ajax . Então você deve garantir que esse contêiner idexista.

Exemplo de código (simplificado):

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

Para obter um exemplo de código completo, consulte: Como adicionar mais opções para rádios de tipo, use Ajax no Drupal 8 .

kenorb
fonte