У меня есть форма с несколькими шагами, и я реализую форму викторины.
Первый шаг - это экран приветствия с кнопкой «только текст» и «Отправить». Когда пользователь нажимает кнопку «Пуск» (отправить), он увеличивает шаг и перемещает его к следующему шагу, на следующем шаге используются различные элементы формы и кнопка «Отправить».
форма работает правильно, мне нужно изменить форму, используя ajax и без перезагрузки всей страницы.
следующий код демонстрирует мой текущий класс формы без ajax, и он работает как положено:
class QuestionsForm extends FormBase
{
protected $definedSteps = 3;
protected $questionService;
protected $questions = [
[
'question_text' => 'Q1',
'answers' =>
[
'1' => 'a',
'2' => 'b'
]
],
[
'question_text' => 'Q2',
'answers' =>
[
'1' => 'a',
'2' => 'b'
]
],
[
'question_text' => 'Q3',
'answers' =>
[
'1' => 'a',
'2' => 'b'
]
],
];
protected $step = '';
protected $steps = [];
protected $complete = FALSE;
public function __construct()
{
$this->steps[0] = 0; // Create Hello Screen Step
for ($i = 1; $i <= $this->definedSteps; $i++) {
$this->steps[$i] = $i; // Create Questions Steps
if ($i == $this->definedSteps) {
$this->steps[$i + 1] = $i + 1; // Create Results Step
$this->steps[$i + 2] = $i + 2; // Create Submit Data Step
}
}
if (!$this->step) {
$this->step = $this->steps[0];
}
}
/**
* {@inheritdoc}
*/
public function getFormId()
{
return 'xxxform';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state)
{
if ($this->step == 0) {
$this->stepStartScreen($form, $form_state);
}
else if ($this->step == 1) {
$this->stepOne($form, $form_state);
}
else if ($this->step == 2) {
$this->stepTwo($form, $form_state);
}
else if ($this->step == 3) {
$this->stepThree($form, $form_state);
}
else if ($this->step == 4) {
$this->stepResult($form, $form_state);
}
else if ($this->step == 5) {
$this->stepReview($form, $form_state);
}
return $form;
}
/**
* {@inheritdoc}
*/
private function stepStartScreen(array &$form, FormStateInterface $form_state)
{
$form['welcome_message'] = [
'#markup' => '<p id="welcome_text">Press start to begin!</p>',
];
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Next'),
'#id' => 'next',
];
}
/**
* {@inheritdoc}
*/
private function stepOne(array &$form, FormStateInterface $form_state)
{
$form['q']['question'] = [
'#type' => 'radios',
'#title' => $this->questions[0]['question_text'],
'#required' => TRUE,
'#options' => $this->questions[0]['answers'],
];
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Next'),
'#id' => 'next',
'#ajax' => [
'callback' => '::submitForm'
],
];
}
private function stepTwo(array &$form, FormStateInterface $form_state)
{
$form['q']['question'] = [
'#type' => 'radios',
'#title' => $this->questions[1]['question_text'],
'#required' => TRUE,
'#options' => $this->questions[1]['answers'],
];
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Next'),
'#id' => 'next',
];
}
private function stepThree(array &$form, FormStateInterface $form_state)
{
$form['q']['question'] = [
'#type' => 'radios',
'#title' => $this->questions[2]['question_text'],
'#required' => TRUE,
'#options' => $this->questions[2]['answers'],
];
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Next'),
'#id' => 'next',
];
}
/**
* Review step of form
*
* @param array $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*/
private function stepResult(array &$form, FormStateInterface $form_state)
{
$form['actions']['try_again'] = [
'#type' => 'submit',
'#value' => $this->t('Try Again'),
'#id' => 'try_again',
'#validate' => [],
'#limit_validation_errors' => [],
'#submit' => [],
];
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Submit your score.'),
'#id' => 'next',
];
}
/**
* Review step of form
*
* @param array $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*/
private function stepReview(array &$form, FormStateInterface $form_state)
{
$form['review']['fullname'] = [
'#type' => 'textfield',
'#title' => $this->t('Full Name'),
'#required' => TRUE,
];
$form['review']['email'] = [
'#type' => 'email',
'#title' => $this->t('Email Address'),
'#description' => $this->t('Enter your email address and you\'ll be entered into a prize draw'),
'#default_value' => $email ? $email : NULL,
'#required' => TRUE,
];
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Submit Result'),
'#id' => 'next',
];
}
/**
* @param array $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*
* @throws \Exception
*/
public function submitForm(array &$form, FormStateInterface $form_state)
{
$step_key = array_search($this->step, $this->steps);
if ($this->step == $this->definedSteps + 2) {
$this->stepReviewSubmit($form, $form_state);
}
if ($this->complete) {
return;
}
if ($form_state->getTriggeringElement()['#id'] == 'back') {
// Move to previous step
$this->step = $this->steps[$step_key - 1];
} else if ($form_state->getTriggeringElement()['#id'] == 'try_again') {
return;
} else {
// Move to next step.
$this->step = $this->steps[$step_key + 1];
}
$form_state->setRebuild();
}
/**
* @param array $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*
* @throws \Exception
*/
public function stepReviewSubmit(array &$form, FormStateInterface &$form_state)
{
drupal_set_message($this->t('Thank you for your submission'), 'status');
$this->complete = TRUE;
}
}
Как я могу выполнить это функционально для визуализации форм после отправки, используя ajax для замены старого и добавления нового.
Мне нужен ajax только в фазе шагов, так что форма 1 может быть нормальной, тогда формы шагов должны быть с ajax, и после этой последней формы он также может быть нормальным.
Извините за длинный текст:)
Что я пытался сделать, я использовал ajax, подобный этому '#ajax' => ['callback' => ':: submitForm'], для всех кнопок отправки, а затем в buildForm, возвращая ответ вместо формы в пошаговые функции как таковые, но они не работают:
else if ($this->step == 2) {
$this->stepTwo($form, $form_state);
$renderer = \Drupal::service('renderer');
$response = new AjaxResponse();
$response->addCommand(new ReplaceCommand('#some_element',$renderer->render($x)));
return $response;
}