drupal - 如何从 Drupal 8 中的 hook_form_alter 将参数传递给 ajax 回调
问题描述
我正在尝试实现一个 hook_form_alter 方法,通过节点的表单显示中的 ajax 回调来修改一个字段的行为。
这个想法是当我从选择列表字段(field_country)中选择一个选项时,修改其他字段列表(field_laws)的值。具体来说,当我选择一个国家时,钩子方法通过 ajax 回调将此值(当前)传递给changeLawsData。此回调获取一个外部服务,该服务返回一组由先前选择的国家/地区过滤的值。
问题出在回调方法内部,我无法访问包含先前 hook_form_alter 的 $form 和 $form_state 对象。
我的问题是:是否可以通过参数将此对象传递给回调?例如,有了这个我可以处理表单的状态及其字段。
像这样的东西:
$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;
}
}
非常感谢大家。
解决方案
您需要在 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;
}
}
请记住,上面是一个例子......
推荐阅读
- java - 从 Firebase 检索数据,但 snaptshop.get 返回 null
- c# - 如何将 JSON 作为原始 PostgreSQL 类型传递给使用 Dapper 的函数?
- android - Chaquopy 无法下载 NLTK 资源
- travis-ci - 将 .travis.yml 存储在 .travis 文件夹或其他位置
- python - 检测到 I2C 传感器但没有响应
- javascript - const { target: { files } } = event 在javascript中是什么意思?
- git - 编辑过去提交的补丁
- java - Gradle 5 jar.destinationDirectory
- javascript - JS记忆卡游戏-如何防止用户同时翻转超过2张卡
- c - stb_truetype.h 和 SDL2 改变字体颜色