我在修改drupal 8中的表单时遇到了多个AJAX请求的问题。
让我解释一下 - 我一直在尝试在drupal中构建一个测验模块,并决定使用一个小部件来创建可变数量的测验问题,在这个问题小部件中是一个可能的答案列表。 我在我的问题小部件中创建了一个AJAX按钮,它允许删除答案并在第一次提交时工作,但由于某种原因第二次运行ajax调用时表单被重置(就像没有进行任何更改一样,并没有删除任何答案)。在我取消设置答案之后,我已经调试了表单数组,以及第二次运行ajax回调时。
启用ajax的按钮使用默认的ajax replace方法,我尝试了在我的AJAX回调中返回表单(减去答案)的不同方法,包括简单地取消设置所选表单元素并返回表单,以及使用AjaxResponse和HtmlCommand类。我还尝试通过formbuilder和form_state重建表单,但没有任何乐趣。 此外,每个按钮和答案都有唯一的名称/ ID。
这是我的小部件代码(包括按钮定义):
<?php
/**
* @file
* Contains \Drupal\pp_quiz\Plugin\Field\FieldWidget\QuestionWidget.
*/
namespace Drupal\pp_quiz\Plugin\Field\FieldWidget;
use Drupal\pp_quiz\Controller\QuizController;
use Drupal\pp_quiz\Ajax\AjaxHandler;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Plugin implementation of the 'question_widget' widget
*
* @FieldWidget(
* id = "question_widget",
* label = @Translation("Quiz question widget"),
* field_types = {
* "quizquestion_type",
* },
* )
*/
class QuestionWidget extends WidgetBase
{
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$ajaxhandler = new AjaxHandler();
$input = $form_state->getUserInput();
//grab answer count from element array (using delta index)
$question = $items->get($delta)->getValue();
$answercount = count(unserialize($question['answer']));
$element['question'] = array(
'#type'=>'text_format',
'#format' => 'normal',
'#title' => gettext('Question'),
'#description' => gettext("The Question Text"),
'#required' => TRUE,
'#element_validate' => array(
array(
'\Drupal\pp_quiz\Controller\QuizController',
'validateQuestion'
),
),
);
$element['answers_description'] = array('#markup' => 'Create answers below and select which are correct by checking boxes');
$tableheader = array(
'answer' => array('data' => t('Answer'), 'field' => 'answer'),
);
for ($i=0; $i<$answercount; $i++) {
$name = "{$delta}answer{$i}";
$options[$name] = array(
'answer' => array(
'data' => array(
'#type'=>'textfield',
//fix for losing answers on addmore button
'#value'=>isset($input[$name]) ? $input[$name] : '',
'#name' => $name,
'#required' => TRUE,
),
),
);
}
$element['answers'] = array(
'#type'=>'tableselect',
'#header' => $tableheader,
'#options' => $options,
);
$element['removeanswer'] = array(
'#type' => 'submit',
'#value' => t('Remove Answer'),
'#name' => "{$delta}removeanswer",
'#questionno' => $delta,
'#attributes' => array(
'class' => array('removeanswer')
),
'#ajax' => array(
'callback' => array(
$ajaxhandler,
'removeAnswerAjax',
),
'wrapper' => 'edit-field-quiz-questions-wrapper',
),
);
$element = array(
'#type' => 'question',
) + $element;
return $element;
}
}
正如您在上面所看到的,我的'removeanswer'提交按钮元素对类'AjaxHandler'上的一个名为'removeAnswerAjax'的函数进行了ajax回调。以下是此回调的代码:
<?php
/**
* @file
* Contains \Drupal\pp_quiz\Ajax\AjaxHandler.
*/
namespace Drupal\pp_quiz\Ajax;
use \Drupal\pp_quiz\Controller\QuizController;
use \Drupal\pp_quiz\Entities\QuizResults;
use \Drupal\Core\Form\FormStateInterface;
use \Drupal\Core\Ajax\AjaxResponse;
use \Drupal\Core\Ajax\HtmlCommand;
class AjaxHandler {
public function removeAnswerAjax(&$form, FormStateInterface $form_state) {
$questionno = $form_state->getTriggeringElement()['#questionno'];
$response = new AjaxResponse();
//find selected answer for question number (questionno)
foreach($form['field_quiz_questions']['widget'][$questionno]['answers']['#value'] as $answer_key=>$answer) {
unset($form['field_quiz_questions']['widget'][$questionno]['answers']['#options'][$answer]);
unset($form['field_quiz_questions']['widget'][$questionno]['answers']['#default_value'][$answer]);
unset($form['field_quiz_questions']['widget'][$questionno]['answers'][$answer]);
}
$response->addCommand(new HtmlCommand('#edit-field-quiz-questions-wrapper', $form['field_quiz_questions']['widget']));
$form_state->setRebuild();
return $response;
}
}
如果有人能够在将表单作为参数传递给我的ajax回调之前解释为什么表单被重置,我会永远爱你: - )
感谢阅读。
答案 0 :(得分:0)
Ajax没有第二次生效的一个可能原因是在Ajax回调中重建表单。当您使用 -
重建表单时$form_state->setRebuild()
重建表单时,所有字段和表单ID都以随机内部版本号为后缀。因此找不到选择器,并且不会在DOM中替换响应。
尝试删除表单重建。