【问题标题】:Drupal 8 Ajax forgetting form changesDrupal 8 Ajax 忘记表单更改
【发布时间】:2016-04-10 13:09:03
【问题描述】:

我遇到了多个 AJAX 请求在 drupal 8 中修改表单的问题。

让我解释一下 - 我一直在尝试在 drupal 中构建一个测验模块,并决定使用一个小部件来创建可变数量的测验问题,在这个问题小部件中是一个可能答案的列表。 我在我的问题小部件中创建了一个 AJAX 按钮,它允许删除答案并且它在第一次提交时工作,但由于某种原因,我第二次运行 ajax 调用时表单被重置(就像没有进行任何更改,并且没有删除任何答案)。在取消设置答案后以及第二次运行 ajax 回调时,我已经调试了表单数组。

启用 ajax 的按钮使用默认的 ajax 替换方法,我尝试了在我的 AJAX 回调中返回表单(减去答案)的不同方法,包括简单地取消设置选定的表单元素并返回表单,以及使用 AjaxResponse和 HtmlCommand 类。我还尝试通过formbuilderform_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 回调之前解释为什么要重置表单,我会永远爱你 :-)

感谢阅读。

【问题讨论】:

  • 你弄明白了吗?

标签: php ajax drupal widget drupal-8


【解决方案1】:

您的 Ajax 第二次未生效的一个可能原因是在 Ajax 回调中重建表单。当您使用 - 重建表单时 -

$form_state->setRebuild()

重新构建表单时,所有字段和表单 ID 都以随机构建号作为后缀。因此没有找到选择器,并且没有在 DOM 中替换响应。

尝试删除表单重建。

【讨论】:

  • 感谢您,我设法找到了如何让 ajax 提交没有值的重建表单。你能指出我整个构建/重建过程吗?我的意思是它的起点-终点。剩下的我都知道了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-07
  • 2020-02-13
  • 2016-08-06
  • 2017-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多