По мотивам предыдущего поста про многошаговые формы — пример двухшаговой формы, в которой второй шаг показывается в модальном окне:
class ExampleTwoStepForm extends FormBase {
/**
* {@inheritDoc}
*/
public function getFormId(): string {
return 'example_two_step_form';
}
/**
* {@inheritDoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$step = (int)$form_state->get('step');
if (!$step) {
$step = 1;
$form_state->set('step', $step);
$form_state->set('steps_values', []);
}
return $this->{'buildStep' . $step}($form, $form_state);
}
/**
* Build step 1.
*/
public function buildStep1(array $form, FormStateInterface $form_state): array {
$form['first_name'] = [
'#type' => 'textfield',
'#title' => 'First name',
];
$form['next'] = [
'#type' => 'submit',
'#value' => 'Next',
'#name' => 'next',
'#submit' => ['::nextButtonSubmit'],
'#ajax' => ['callback' => '::nextButtonAjax'],
];
return $form;
}
/**
* "Next" button submit callback.
*/
public function nextButtonSubmit(array $form, FormStateInterface $form_state): void {
$form_state->set('step', 2);
// Store current values to all-steps values
$steps_values = $form_state->get('steps_values') ?? [];
$steps_values = NestedArray::mergeDeep($steps_values, $form_state->cleanValues()->getValues());
$form_state->set('steps_values', $steps_values);
// Copy all-steps values to current values
$form_state->setValues($steps_values);
// Disable form reload (redirect)
$form_state->setRebuild();
}
/**
* "Next" button ajax callback.
*/
public function nextButtonAjax(array $form, FormStateInterface $form_state): AjaxResponse {
$response = new AjaxResponse();
$response->addCommand(new UpdateBuildIdCommand($form['#build_id'], $form['#build_id_old']));
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
$response->addCommand(new OpenModalDialogCommand('Step 2', $form));
return $response;
}
/**
* Build step 2.
*/
public function buildStep2(array $form, FormStateInterface $form_state): array {
$form['last_name'] = [
'#type' => 'textfield',
'#title' => 'Last name',
];
$form['finish'] = [
'#type' => 'submit',
'#value' => 'Submit',
'#name' => 'finish',
];
return $form;
}
/**
* {@inheritDoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
$steps_values = $form_state->get('steps_values') ?? [];
$values = NestedArray::mergeDeep($steps_values, $form_state->cleanValues()->getValues());
dsm($values);
}
}
Как всегда не обошлось без подводных камней. Если пользователь нажал на кнопку "Next", потом закрыл модальное окно и снова нажал кнопку "Next", то вызовется submitForm()
, а не nextButtonSubmit()
, как ожидается. Так происходит потому, что перед открытием модалки друпал обновит form_build_id
основной формы и при последующих отправках будет думать, что пользователь сабмитит второй шаг. Именно поэтому в nextButtonAjax()
возвращаем старый form_build_id
с помощью new UpdateBuildIdCommand($form['#build_id'], $form['#build_id_old'])
Написанное актуально для
Drupal 8+
Похожие записи
- Сделать чтобы форма входа открывалась в диалоге
- Открыть страницу или форму в диалоговом окне
- Показать в jQuery UI Dialog результат отправки формы
- Навесить на элемент managed_file свой ajax callback (Как обновить всю форму при загрузки файла в managed_file)
- Восстанавливаем позицию текстового курсора при ajax обновлении формы
Комментарии
dsm($values); забыл удалить :)
Это же демо
Добавить комментарий