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
相关产品推荐
相关产品推荐

