Отправка формы Ajax не работает во второй раз
Я загружаю форму узла/редактирования в блок и добавляю ajax при отправке.
Я добавляю Ajax в hook_form_alter.
$form['#prefix'] = '<div id="' . $form_wrapper . '">';
$form['#suffix'] = '</div>';
$form['actions']['submit']['#submit'][] = 'submitForm';
$form['actions']['submit']['#ajax'] = array(
'callback' => 'my_ajax_callback',
'wrapper' => $form_wrapper,
'effect' => 'fade',
);
Форма для отправки:
function submitForm(array &$form, FormStateInterface $form_state){
$input = $form_state->getUserInput();
$form_state->setUserInput($input);
$form_state->setRebuild(TRUE);
}
И обратный вызов:
function my_ajax_callback(&$form, FormStateInterface $form_state, $form_id) {
$form_state->setRebuild();
return $form;
}
Первый раз работает нормально. Второй раз, кажется, работает без каких-либо ошибок, но он не отправляет мои новые данные.
Я проверил этот комментарий Как я могу реализовать отправку формы AJAX? но я не знаю, нужно ли мне устанавливать значения в form_state. Также я использую этот обратный вызов для нескольких типов контента. Должен ли я проверять и устанавливать значение для каждого поля? Есть ли лучший способ?
Спасибо за вашу помощь!
------ РЕДАКТИРОВАТЬ -----
Я добавил функцию формы отправки, и теперь при повторной отправке я получаю "Содержимое либо было изменено другим пользователем, либо вы уже отправили изменения. В результате ваши изменения не могут быть сохранены.'.
Кроме того, должен ли я получить/установить каждое из своих полей или $input= $form_state->getuserinput(); $form_state->setuserinput($ввод); достаточно ли?
-------- ОБНОВЛЕНИЕ ------
Мне удалось заставить его работать с формами, которые должны быть пустыми после отправки ajax, используя приведенный ниже код:
В hook_form_alter:
$form['wrapper'] = array(
'#type' => 'container',
'#attributes' => array('id' => $form_wrapper),
);
$prefix = '<div id="' . $form_wrapper . '">';
$form['#prefix'] = $prefix;
$form['#suffix'] = '</div>';
$form['actions']['submit']['#submit'][] = 'Drupal\MY_MODULE\Plugin\Form\FormAlter::ajaxFormEntityFormSubmitEmptyForm';
$form['actions']['submit']['#ajax'] = array(
'callback' => 'Drupal\MY_MODULE\Plugin\Form\FormAlter::ajaxFormEntityCallbackEmptyForm',
'wrapper' => $form_wrapper,
'effect' => 'fade',
);
И в FormAlter.php :
/**
* Rebuild the form - Empty form.
*/
public static function ajaxFormEntityFormSubmitEmptyForm($form, &$form_state){
$entity = $form_state->getBuildInfo()['callback_object']->getEntity();
$entity_type = $entity->getEntityTypeId();
$bundle = $entity->bundle();
$new_entity = \Drupal::entityTypeManager()->getStorage($entity_type)->create(['type' => $bundle]);
$form_state->getBuildInfo()['callback_object']->setEntity($new_entity);
// Clear user input.
$input = $form_state->getUserInput();
$clean_keys = $form_state->getCleanValueKeys();
$clean_keys[] = 'ajax_page_state';
foreach ($input as $key => $item) {
if (!in_array($key, $clean_keys) && substr($key, 0, 1) !== '_') {
unset($input[$key]);
}
}
$input['entity'] = $entity;
$form_state->setUserInput($input);
// Rebuild the form state values.
$form_state->setRebuild();
$form_state->setStorage([]);
}
/**
* Ajax callback to handle just returns the form
*/
public static function ajaxFormEntityCallbackEmptyForm(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
if ($form_state->hasAnyErrors()) {
return $form;
}
else {
return $form;
}
}
Теперь я пытаюсь сделать что-то подобное, но я хочу, чтобы форма была заполнена новыми значениями. Поэтому я создал две новые функции в FormAlter:
/**
* Rebuild the form.
*/
public static function ajaxFormEntityFormSubmit($form, &$form_state) {
$entity = $form_state->getBuildInfo()['callback_object']->getEntity();
$entity_type = $entity->getEntityTypeId();
$bundle = $entity->bundle();
$new_entity = \Drupal::entityTypeManager()->getStorage($entity_type)->create(['type' => $bundle]);
$form_state->getBuildInfo()['callback_object']->setEntity($new_entity);
$input = $form_state->getUserInput();
$input['entity'] = $entity;
$form_state->setUserInput($input);
if(!$form_state->hasValue('title')){
$form_state->setValue('title',$entity->getTitle());
}
// Rebuild the form state values.
$form_state->setRebuild(TRUE);
$form_state->setStorage([]);
}
/**
* Ajax callback to handle special ajax form entity magic.
*/
public static function ajaxFormEntityCallback(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
// If errors, returns the form with errors and messages.
if ($form_state->hasAnyErrors()) {
return $form;
}
// Else show the result.
else {
$userInputs = $form_state->getUserInput();
$entity = $userInputs['entity'];
$entity_type = $entity->getEntityTypeId();
$response = new AjaxResponse();
if ($entity_type == 'node') {
$title = $entity->getTitle();
}
return $form;
}
}
Если я верну форму $ в обратный вызов, в первый раз работает нормально, но во второй я получаю две ошибки в журнале:
Drupal\Ядро\База данных\Исключение Integrityconstraintviolationexception: SQLSTATE[23000]: Нарушение ограничения целостности: 1048 Столбец "заголовок" не может быть пустым: ВСТАВЬТЕ В {node_field_data} (nid, vid, тип, код языка, статус, заголовок, uid, созданный, измененный, продвигаемый, липкий, измененный, измененный, измененный, измененный по умолчанию) ЗНАЧЕНИЯ (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10,:db_insert_placeholder_11, :db_insert_placeholder_12); Массив ([:db_insert_placeholder_0] => 201 [:db_insert_placeholder_1] => 258 [:db_insert_placeholder_2] => my_estate_details [:db_insert_placeholder_3] =>ru [:db_insert_placeholder_4] => 1 [:db_insert_placeholder_5] => [:db_insert_placeholder_6] => 5 [:db_insert_placeholder_7] => 1500889059 [:db_insert_placeholder_8] => 1500889066 [:db_insert_placeholder_9] => 0 [:db_insert_placeholder_10] => 0 [:db_insert_placeholder_11] => 1 [:db_insert_placeholder_12] => 1) в Drupal\Ядро\База данных\Подключение->Исключение Handlequeryexception()
И
Исключение Drupal\Core\Entity\entitystorageexception: Состояние SQLSTATE[23000]: Нарушение ограничения целостности: Столбец 1048 "заголовок" не может быть пустым: ВСТАВИТЬ В {node_field_data} (нид вид, тип, langcode, статус, звание, номер uid, созданы, изменены, поощрения, липкий, revision_translation_affected, default_langcode) значения (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11, :db_insert_placeholder_12); Массив ( [:db_insert_placeholder_0] => 201 [:db_insert_placeholder_1] => 258 [:db_insert_placeholder_2]=>my_estate_details_детали [:db_insert_placeholder_3] => ru [:db_insert_placeholder_4] => 1 [:db_insert_placeholder_5] => [:db_insert_placeholder_6] => 5 [:db_insert_placeholder_7] => 1500889059 [:db_insert_placeholder_8] => 1500889066 [:db_insert_placeholder_9] => 0 [:db_insert_placeholder_10] => 0 [:db_insert_placeholder_11] => 1 [:db_insert_placeholder_12] => 1) в Drupal\Core\Entity\Sql\sqlcontententitystorage->сохранить()
В случае, если я верну $response (что я предпочитаю, чтобы иметь возможность изменять сообщение и т. Д.), Первый раз работает нормально, но во второй раз я получаю сообщение:
Содержимое либо было изменено другим пользователем, либо вы уже внесли изменения. В результате ваши изменения не могут быть сохранены.'.
Приношу извинения за длинное сообщение. Какой-нибудь идея/помощь будут полезны!
Заранее благодарю.
1 answers
Мне удалось найти решение.
В моем hook_form_alter:
$form['#attributes']['class'][] = $ajax_id;
$form['actions']['submit']['#submit'][] = 'Drupal\MY_MODULE\Plugin\Form\FormAlter::ajaxFormEntityFormSubmit';
$form['actions']['submit']['#ajax'] = array(
'callback' => 'Drupal\MY_MODULE\Plugin\Form\FormAlter::ajaxFormEntityCallback',
'wrapper' => $ajax_id,
'effect' => 'fade',
);
$form['ajax_form_entity'] = [
'#type' => 'hidden',
'#value' => [
'reload' => '.reload',
'form_selector' => '.' . $ajax_id,
'show_message' => TRUE,
]
];
public static function ajaxFormEntityFormSubmit($form, &$form_state) {
$entity = $form_state->getBuildInfo()['callback_object']->getEntity();
// Clear user input.
$input = $form_state->getUserInput();
// We should not clear the system items from the user input.
$clean_keys = $form_state->getCleanValueKeys();
$clean_keys[] = 'ajax_page_state';
foreach ($input as $key => $item) {
if (!in_array($key, $clean_keys) && substr($key, 0, 1) !== '_') {
unset($input[$key]);
}
}
// Store new entity for display in the AJAX callback.
$input['entity'] = $entity;
$form_state->setUserInput($input);
// Rebuild the form state values.
$form_state->setRebuild();
$form_state->setStorage([]);
}
И обратный вызов:
public static function ajaxFormEntityCallback(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
// If errors, returns the form with errors and messages.
if ($form_state->hasAnyErrors()) {
return $form;
}
// Else show the result.
else {
$userInputs = $form_state->getUserInput();
$entity = $userInputs['entity'];
$entity_type = $entity->getEntityTypeId();
$configurations = $form_state->getValue('ajax_form_entity');
$response = new AjaxResponse();
// Get messages even if not shown.
$status_messages = array('#type' => 'status_messages');
$message = \Drupal::service('renderer')->renderRoot($status_messages);
// Reload the form.
$response->addCommand(new ReplaceCommand($configurations['form_selector'], $form));
return $response;
}
}