Jak odbudować formularz po wywołaniu AJAX

12

Usiłuję umożliwić użytkownikowi dynamiczny wybór liczby pól na podstawie listy rozwijanej za pomocą wywołania ajax, ale nie mogę uzyskać połączenia wywoływanego przez ajax, aby później odbudować formularz.

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

Liczba pól tekstowych jest oparta na zmiennej „liczba” form_state. Wywołanie zwrotne columnCallback zmienia zmienną form_state na 10 i jest uruchamiane po zmianie pola formularza „columnNum”. Jednak formularz nie jest przebudowywany z nową liczbą pól, mimo że $ form_state-> setRebuild (); nazywa się. Czy istnieje sposób na przebudowanie formularza po wywołaniu ajax?

UWAGA: Próbowałem już takich technik, jak zamiana lub dopisywanie elementów formularza wewnątrz rzeczywistego wywołania ajax, ale kiedy tak się dzieje, żadne dane wejściowe do zastąpionych pól nie są przekazywane do $ form_state.

AKTUALIZACJA: Po próbie rozwiązania 4k4 pojawia się błąd

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

Uważa się, że błąd występuje, ponieważ $ form ['column'] zwraca wartość null, mimo że został utworzony jako kontener w funkcji blockForm. Próbowałem oddzwonić na inne sposoby

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

i

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

Ale otrzymuję ten sam błąd. Co ciekawe, kiedy zmieniam wywołanie zwrotne, aby zwracać cały formularz $ zamiast tylko $ form [„kolumna”], powtarza formularz (kopia formularza pojawia się pod bieżącym formularzem) i nadal bez odpowiedniej liczby kolumn.

Matt
źródło
Może to być literówka, ale podwójne sprawdzanie, czy wiesz, że w columnCallback pierwszym argumentem jest literówka (bez spacji między tablicą a formą $)?
Kevin

Odpowiedzi:

4

Pierwszym problemem jest obsługa wartości numeru kolumny. Przy pierwszej kompilacji pobierz go z konfiguracji, przy przebudowie pobierz go z danych wejściowych użytkownika i włóż $columnNum.

Drugim jest decyzja, która część formularza zmieni się w AJAX i umieść to w pojemniku div z identyfikatorem 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;
    }

W wywołaniu zwrotnym musimy tylko zwrócić opakowanie ajax.

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

Drupal odbudowuje formularz przy każdym żądaniu ajax i umieszcza go w parametrze $formwywołania zwrotnego. Nie ma sensu próbować go odbudowywać.

4k4
źródło
1
Otrzymuję błąd po wywołaniu żądania ajax. „Kod wyniku HTTP: 200” StatusText: OK Odpowiedź Odpowiedź:
Matt
1
Testowe rzeczy, które wykonałem na die (print_r ($ form_state-> getValues ​​())); i poprawnie wyświetlał prawidłową wartość columnNum. W przeciwnym razie popełni błąd.
Matt
1
Pokazałem zmiany w twoim kodzie. Nie można pomóc w debugowaniu bez komunikatów o błędach z numerami linii.
4k4
2
Czy usunąłeś błąd składniowy z komentarza @ Kevin? Czy w dzienniku błędów są błędy php? Podczas testowania nowego kodu powinno być dużo.
4k4
2
Wyśledził błąd, co oznacza, że return $form['column']jest pusty, ponieważ zwracana wartość jest odznaczana renderResponse(). Nadal może występować problem z listą parametrów wywołania zwrotnego, ponieważ w tym formularzu umieszczamy co najmniej kontener, co zapobiegnie temu błędowi.
4k4
2

Chyba brakuje Ci wrappermetody w '#ajax'(obok callback), która zawiera idatrybut HTML obszaru, w którym powinna zostać umieszczona treść zwrócona przez wywołanie zwrotne. Zobacz: Ajax API . Następnie upewnij się, że taki kontener idistnieje.

Przykład kodu (uproszczony):

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

Aby uzyskać pełny przykład kodu, zobacz: Jak dodać więcej opcji dla radiotelefonów, użyj Ajax w Drupal 8 .

kenorb
źródło