Отправка формы 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 (что я предпочитаю, чтобы иметь возможность изменять сообщение и т. Д.), Первый раз работает нормально, но во второй раз я получаю сообщение:

Содержимое либо было изменено другим пользователем, либо вы уже внесли изменения. В результате ваши изменения не могут быть сохранены.'.

Приношу извинения за длинное сообщение. Какой-нибудь идея/помощь будут полезны!

Заранее благодарю.

Author: Ismini, 2017-06-19

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;
    }
  }
 0
Author: Ismini, 2017-07-27 13:57:43