Как передать параметр в обратный вызов ajax из hook_form_alter в Drupal 8 - PullRequest
0 голосов
/ 08 мая 2020

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

Идея состоит в том, когда я выбираю один вариант из поля списка выбора (field_country) изменить значения другого списка полей (field_l aws). В частности, когда я выбираю одну страну, метод перехвата передает это значение (текущее) через ajax обратный вызов changeLawsData . Этот обратный вызов получает одну внешнюю службу, которая возвращает один массив значений, отфильтрованных по стране, выбранной ранее.

Проблема находится внутри метода обратного вызова, я не могу получить доступ к объектам $ form и $ form_state, которые содержат предыдущий hook_form_alter .

Мой вопрос: можно ли передать эти объекты с помощью аргументов в функцию обратного вызова? С помощью этого я мог бы, например, обработать состояние формы и ее поля.

Примерно так:

    $form['field_country']['widget']['#ajax'] = array(
        'callback' => [$this,'changeLawsData'],
        'event' => 'change',
        'disable-refocus' => FALSE,
        **'arguments' = array($form, $form_state)**
      );

Вот полный код этой реализации.

<?php

namespace Drupal\obs_urban_system\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
/**
 * Our event subscriber class.
 */
class NodeUrbanSystemFormAlterEventSubscriber implements EventSubscriberInterface {
    public static function getSubscribedEvents() {
        return [
            HookEventDispatcherInterface::FORM_ALTER => 'hookFormAlter'
        ];
    }

    /**
     * Implements hook_form_alter
     */
    public function hookFormAlter($event) {

        if($event->getFormId() == 'node_urban_system_edit_form') {
            $form = $event->getForm();
            $country = $form['field_country']['widget']['#default_value'];
            $form['field_laws']['widget'][0]['value']['#options'] = \Drupal::service('custom_services.law')->getLawsByContent($country, 'country');
            $form['field_law_articles']['widget'][0]['value']['#options'] = \Drupal::service('custom_services.law')->getLawArticlesByCountry($country);
            $form['field_country']['widget']['#ajax'] = array(
                'callback' => [$this,'changeLawsData'],
                'event' => 'change',
                'disable-refocus' => FALSE
              );
            $event->setForm($form);
        }
    }

    /**
     * @param $form
     * @param \Drupal\Core\Form\FormStateInterface $form_state
     * @return \Drupal\Core\Ajax\AjaxResponse
     */
    function changeLawsData(&$form, FormStateInterface $form_state) {
<!--- HERE IM USING THE $form object --->
        $country = $form['field_country']['widget']['#default_value'];
<!---                                --->
        $laws = \Drupal::service('custom_services.law')->getLawsByContent($country, 'country');

        foreach ($laws as $key => $value) {
            $option .= "<option value='" . $key . "'>" . $value . " </option>";
        }

        $response = new AjaxResponse();
        $response->addCommand(new HtmlCommand('#edit-field-laws-0-value', $option));
        return $response;
    }

}

Большое спасибо всем.

1 Ответ

0 голосов
/ 08 мая 2020

Вам необходимо выполнить все манипуляции с формой в form_alter.
Когда будет запущен обратный вызов ajax, форма будет перестроена, и текущие значения формы будут доступны в form_state.
Ваш ajax обратный вызов должен возвращать только то, что необходимо во внешнем интерфейсе, он не должен фактически управлять массивом формы.

Вот пример вашего кода (только пример, непроверенный)

<?php

namespace Drupal\obs_urban_system\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
/**
 * Our event subscriber class.
 */
class NodeUrbanSystemFormAlterEventSubscriber implements EventSubscriberInterface {
    public static function getSubscribedEvents() {
        return [
            HookEventDispatcherInterface::FORM_ALTER => 'hookFormAlter'
        ];
    }

    /**
     * Implements hook_form_alter
     */
    public function hookFormAlter($event) {

        if($event->getFormId() == 'node_urban_system_edit_form') {
            $form = $event->getForm();
            $country = $form['field_country']['widget']['#default_value'];

            // Get the form state object.
            $form_state = $event->getFormState();
            // Here we should check if a country has been selected.
            $country = $form_state->getValue('country');
            if ($country) {
              // populate the options from service here.
              $form['field_laws']['widget']['#options'] = \Drupal::service('custom_services.law')->getLawsByContent($country, 'country');
            } else {
              // Populate with default options.
              $form['field_laws']['widget']['#options'] = [];
            }


            $form['field_law_articles']['widget'][0]['value']['#options'] = \Drupal::service('custom_services.law')->getLawArticlesByCountry($country);
            $form['field_country']['widget']['#ajax'] = array(
                'callback' => [$this,'changeLawsData'],
                'event' => 'change',
                'disable-refocus' => FALSE
              );
            $event->setForm($form);
        }
    }

    /**
     * @param $form
     * @param \Drupal\Core\Form\FormStateInterface $form_state
     * @return \Drupal\Core\Ajax\AjaxResponse
     */
    function changeLawsData(&$form, FormStateInterface $form_state) {
        $response = new AjaxResponse();
        $response->addCommand(new HtmlCommand('#edit-field-laws', $form['field_laws']));
        return $response;
    }

}

Помните, что приведенный выше пример ...

...