You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drupal 9.5中通过AJAX修改表单隐藏字段has_photo的值

Drupal 9.5:通过AJAX动态修改隐藏输入框值

我页面上有两个核心字段:一个按用户ID列出选项的<select>下拉框,以及两个单选按钮。需求是当用户切换下拉框选项时,通过AJAX修改名为has_photo的隐藏输入框的值。

目前我在继承FormBase的buildForm()方法里写了如下表单代码:

$form['card']['user'] = [
  '#type' => 'select',
  '#empty_option' => 'Choose',
  '#options' => $users,
  '#default_value' => $id_user,
  '#ajax' => [
    'method' => 'replace',
    'callback' => '::addPhotoWarning',
    'event' => 'change',
    'wrapper' => 'hasPhoto'
  ],
];

$form['card']['hasPhoto'] = [
  '#type' => 'number',
  '#value' => $hasPhoto
];

对应的AJAX回调函数代码:

/**
 * @param array $form
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *
 * @return void
 */
public function addPhotoWarning(array &$form, FormStateInterface $form_state) {

  $idUser = $form_state->getUserInput()['card']['user'] ?? NULL;
  if ($idUser) {
      $hasPhoto = $this->hasPhoto($idUser);
      $form['card']['user']['#value'] = $hasPhoto ? '1' : '0';
  }
  return $form['card']['hasPhoto'];
}

现在的问题是我把hasPhoto设成了number类型,因为误以为Drupal AJAX API需要容器,找不到直接重载隐藏类型字段值的方法,同时我不想重载整个表单(避免丢失用户在其他输入框中已填写的内容),使用的是Drupal 9.5版本。


解决方案

你不需要用number字段当容器,只需要给隐藏字段套一个容器元素,就能满足Drupal AJAX的替换要求,同时保留隐藏字段的类型。具体修改如下:

1. 修改buildForm()中的表单结构

把隐藏字段放在一个带ID的容器里,AJAX的wrapper指向这个容器的ID:

$form['card']['user'] = [
  '#type' => 'select',
  '#empty_option' => 'Choose',
  '#options' => $users,
  '#default_value' => $id_user,
  '#ajax' => [
    'method' => 'replace',
    'callback' => '::addPhotoWarning',
    'event' => 'change',
    'wrapper' => 'has-photo-wrapper', // 指向容器的ID
  ],
];

// 新增容器作为AJAX替换目标
$form['card']['has_photo_wrapper'] = [
  '#type' => 'container',
  '#attributes' => ['id' => 'has-photo-wrapper'],
];

// 把原number字段改成hidden类型,放在容器内
$form['card']['has_photo_wrapper']['hasPhoto'] = [
  '#type' => 'hidden',
  '#value' => $hasPhoto,
];

2. 修正AJAX回调函数

修复回调里的错误赋值(你之前错误修改了user字段的值),同时用更可靠的方式获取选中的用户ID,最后返回整个容器:

/**
 * @param array $form
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *
 * @return array
 */
public function addPhotoWarning(array &$form, FormStateInterface $form_state) {
  // 通过触发元素获取选中值,比直接取userInput更可靠
  $triggering_element = $form_state->getTriggeringElement();
  $idUser = $form_state->getValue($triggering_element['#parents']);
  
  if ($idUser) {
    $hasPhoto = $this->hasPhoto($idUser);
    // 更新隐藏字段的value
    $form['card']['has_photo_wrapper']['hasPhoto']['#value'] = $hasPhoto ? 1 : 0;
  }
  
  // 返回容器,让AJAX替换整个容器内容
  return $form['card']['has_photo_wrapper'];
}

关键说明

  • Drupal AJAX要求wrapper指向一个存在的DOM元素,隐藏字段本身无法被直接替换,但套一个容器就能解决这个问题
  • 使用$form_state->getTriggeringElement()和getValue()获取选中值,能适应表单结构变化,避免直接访问嵌套数组的潜在错误
  • 回调函数必须返回wrapper指定的元素(这里是容器),AJAX才能正确替换内容,不会影响表单其他字段的输入值

内容的提问来源于stack exchange,提问作者lobafox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 19:57:49