Вы здесь

Как привязать ajax-callback к элементу формы, сгенерированному динамически с помощью другого ajax callback ?

0

Добрый день.

Столкнулся с интересной проблемой.

Например, есть форма, имеющая следующую функцию buildForm

       $form['el1'] = [
            '#type' => 'select',
            '#options' => [
                '1' => 'el1-1',
                '2' => 'el1-2',
                '3' => 'el1-3',
            ],
            '#ajax' => [
                'callback' => '::callback1',
                'wrapper' => 'el2-wrapper',
            ]
        ];

        $form['el2_container'] = [
            '#type' => 'container',
            '#attributes' => [
                'id' => 'el2-wrapper',
            ]
        ];

        $form['el3_container'] = [
            '#type' => 'container',
            '#attributes' => [
                'id' => 'el3-wrapper',
            ]
        ];

        $form_state->setCached(FALSE);

        return $form; 

То есть, форма имеет один select c ajax-каллбэком и два контейнера.

А вот код этого каллбэка.

    public function callback1(array &$form, FormStateInterface $form_state){
        $form['el2_container']['el2'] = [
            '#type' => 'select',
            '#options' => [
                '1' => 'el2-1',
                '2' => 'el2-2',
                '3' => 'el2-3',
            ],
            '#ajax' => [
                'callback' => '::callback2',
            ],
        ];

        return $form['el2_container'];
    }

По замыслу должен добавляться еще один элемент формы внутрь контейнера, имеющий свой каллбэк.

Вот, кстати, код второго каллбэка

public function callback2(array &$form, FormStateInterface $form_state){
        $ar = new AjaxResponse();
        $ar->addCommand(new HtmlCommand('#el3-wrapper', $form_state->getValue('el2')));
        return $ar;
    }

При выборе в первом селекте второй элемент создается, но его #ajax почему-то не инициализируется. То есть, при селекте второго элемента функция callback2 просто не запускается.
И у меня такое ощущение, что ранее это работало нормально, но, возможно, после обновления Drupal с версии 8.3.4 на 8.3.5 работать перестало. Хотя могу и ошибаться.

Никто с таким не сталкивался ? Или в таких случаях нужно ajax у динамически создаваемых элементов как-то инициализировать дополнительно ?

Версия Drupal: 
8.x
Категория: 
Form API
Вопрос задан 07.07.2017 - 08:45

wrapper второй где?

второй сгенерированный элемент работает с каким wrapper
наверное в его ['#ajax'] должно быть указано

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

по моему именно на эту тему была статья на сайте xandeadx.ru

Комментарий оставлен 07.07.2017 - 09:36

Зачем второй wrapper ?
Можно формировать поведение с помощью AjaxResponce.
Например, если нужно сделать несколько действий.

Комментарий оставлен 07.07.2017 - 09:49

Что "оно" ?

В общем, повторяю вопрос.

Возникает ощущение, что этот блок вообще не обработался.
'#ajax' => [
'callback' => '::callback2',
],
Как сделать, чтобы это обрабатывалось ?

Комментарий оставлен 07.07.2017 - 09:56

ваше "формировать поведение с помощью AjaxResponce"
код выполняется только в серверной части

Комментарий оставлен 07.07.2017 - 10:09

Ответы

1

Все элементы формы нужно добавлять в конструкторе формы, ajax callback должен их только возвращать (return $form['...']).

Ответ дан 07.07.2017 - 10:20
Аватар пользователя xandeadx
xandeadx
1527

Хотел Вам сейчас привести пример кода из Examples (AjaxDemo.php), где новый элемент добавляется внутри callback-функции.
Посмотрел ... они в новой версии Examples изменили код и теперь новый элемент уже добавляется внутри buildForm :)

Кстати, а если нужно выполнить несколько JQuery-действий и не обязательно что-то возвращать.
То это так же делать через последовательность $ajax_request->AddCommand(...) ?

Комментарий оставлен 07.07.2017 - 10:46

Если команды не добавляют/удаляют элементы формы, то да.

Комментарий оставлен 07.07.2017 - 13:30

Мне получилось это реализовать через AddCommand даже добавление и удаление элементов.

Например, select c регионами должен отображаться в случае, если страна, выбранная в другом select, имеет регионы.

Вот фрагмент функции buildForm, где отображается список регионов

        $form['region_wrapper'] = [
            '#type' => 'container',
            '#attributes' => [
                'id' => 'region-wrapper'
            ]
        ];

        $regions = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadChildren($country_id);

        if ($regions!=[]){
            $form['region_wrapper']['regions'] = [
                '#type' => 'select',
                '#options' => ['-1' => $this->t('All the regions')] + PalomCountry::getRegionList($country_id),
                '#default_value' => -1,
                '#ajax' => [
                    'callback' => '::changeRegion',
                ]
            ];
        }

А вот фрагмент callback-функции, которая срабатывает при изменении страны и при необходимости подгружает select с регионами.

$ajax_responce = new AjaxResponse();

$regions = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadChildren($form_state->getValue('country'));

if ($regions!=[])
     $ajax_responce->addCommand(new HtmlCommand('#region-wrapper', Ajax::preRenderAjaxForm($form['region_wrapper']['regions'])));
else
    $ajax_responce->addCommand(new HtmlCommand('#region-wrapper', ''));
...
return $ajax_responce;

Для рендеринга использую метод Ajax::preRenderAjaxForm() вместо функции render()

Комментарий оставлен 07.07.2017 - 15:06