Как перестроить форму после вызова AJAX

12

Я пытаюсь позволить пользователю динамически выбирать количество полей на основе раскрывающегося списка с помощью вызова ajax, но я не могу получить вызов ajax, чтобы впоследствии перестроить форму.

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

Количество текстовых полей зависит от переменной form_state 'number'. Функция обратного вызова columnCallback изменяет переменную form_state на 10 и вызывается при изменении поля формы columnNum. Однако форма не перестраивается с новым количеством полей, хотя $ form_state-> setRebuild (); называется. Есть ли способ получить форму для восстановления после вызова AJAX?

ПРИМЕЧАНИЕ. Я уже пробовал такие методы, как замена или добавление элементов формы внутри фактического вызова ajax, но когда это происходит, ни один из входных данных в замененные поля не передается в $ form_state.

ОБНОВЛЕНИЕ: после попытки решения 4k4 я получаю ошибку

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

Предполагается, что ошибка возникает из-за того, что $ form ['column'] возвращает значение null, несмотря на то, что оно было создано в качестве контейнера в функции blockForm. Я пытался вызвать обратный вызов другими способами, такими как

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

и

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

Но я получаю ту же ошибку. Любопытно, что когда я изменяю функцию обратного вызова для возврата всей формы $ вместо просто $ form ['column'], она повторяет форму (копия формы появляется под текущей формой) и все еще без надлежащего числа столбцов.

Matt
источник
Может быть, опечатка, но двойная проверка, знаете ли вы, что в columnCallback первым аргументом является опечатка (без пробела между массивом и & $ form)?
Кевин

Ответы:

4

Первая проблема - обработать значение для номера столбца. При первой сборке получить его из конфигурации, при повторной сборке получить из пользовательского ввода и вставить его $columnNum.

Второй - решить, какая часть формы изменяется в AJAX, и поместить это в контейнер div с идентификатором 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;
    }

В обратном вызове нам нужно только вернуть ajax-оболочку.

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

Drupal перестраивает форму при каждом запросе ajax и помещает ее в параметр $formобратного вызова. Нет смысла пытаться восстановить его снова.

4k4
источник
1
Я получаю сообщение об ошибке после вызова ajax-запроса. 'HTTP Result Code: 200' StatusText: OK ResponseText:
Matt
1
Тестовые вещи, которые я выполнил, умирают (print_r ($ form_state-> getValues ​​())); и он правильно отображал правильное значение columnNum. Это просто ошибки в противном случае.
Мэтт
1
Я внес изменения в ваш код для демонстрации. Не могу помочь с отладкой без сообщений об ошибках с номерами строк.
4k4
2
Вы удалили синтаксическую ошибку из комментария @ Kevin? Есть ли ошибки php в журнале ошибок? При тестировании нового кода должно быть много.
4k4
2
Отследил ошибку, значит return $form['column']ноль, потому что возвращаемое значение не проверяется renderResponse(). Может все еще быть проблема со списком параметров обратного вызова, потому что мы поместили по крайней мере контейнер в этот ключ формы, и это предотвратит эту ошибку.
4k4
2

Я предполагаю, что вы пропустили wrapperметод в вашем '#ajax'(рядом с callback), который состоит из idатрибута HTML области, где должен быть размещен контент, возвращаемый обратным вызовом. Смотрите: Ajax API . Затем вы должны убедиться, что такой контейнер idсуществует.

Пример кода (упрощенно):

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

Для полного примера кода смотрите: Как добавить больше опций для радиостанций типа Ajax в Drupal 8 .

kenorb
источник