Рейтинг:3

Форма AJAX, использующая подкласс ContentEntityForm, запускает/вызывает/вызывает WidgetBase::massageFormValues() дважды

флаг cn

Я использую форму AJAX. Эту форму я строю из подкласса ContentEntityForm. Объект, редактируемый этой формой, имеет поле Мое поле. Чтобы привести все значения полей в соответствующую структуру, которую я использую массажФормаЗначения() в MyFieldWidget класс (подкласс виджетбаза).

Маленькая проблема: метод массажФормаЗначения() вызывается дважды при каждой отправке. Других проблем с формой нет. Я могу правильно редактировать значения в этой форме.

Так что это просто вопрос понимания: почему Drupal вызывает массажФормаЗначения() дважды при каждой отправке.

Упомянутый и мой (очень упрощенный) код:

Мой ajax-контроллер

класс AjaxController расширяет ControllerBase {
  ...
  ...

  публичная функция myController($eid) {

    $myEntity = $this->entityTypeManager()->getStorage('my_entity')->load($eid);
    $form = $this->entityFormBuilder()->getForm($myEntity, 'my_mode');
    $renderer = \Drupal::service('renderer');
    $output = $renderer->renderRoot($form);
  
    $response = новый AjaxResponse();
    $response->addCommand(новый OpenModalDialogCommand($title, $output));
 
    вернуть $ответ;
  }
  ...
  ...
}

Моя Форма является подклассом ContentEntityForm и форма режима для Режим мой_режим организации моя_сущность:

класс MyForm расширяет ContentEntityForm {

 ...
 ...
  действия защищенной функции (массив $form, FormStateInterface $form_state) {
    $actions = parent::actions($form, $form_state);

    $ действия ['отправить'] = [
      '#type' => 'отправить',
      '#значение' => т('Сохранить'),
      '#ajax' => [
        'обратный вызов' => '::ajaxCallback',
        'событие' => 'нажатие мыши',
      ],
    ];

  вернуть действия $;
  }
  ...
  ...
}

Мой класс виджета поля:

class MyFieldWidget расширяет WidgetBase, реализует ContainerFactoryPluginInterface {
...
...

  общедоступная функция massageFormValues ​​(массив $ значений, массив $ форма, FormStateInterface $ form_state) { 

    // ЭТОТ КОД ВЫЗЫВАЕТСЯ ДВАЖДЫ ПРИ КАЖДОЙ ОТПРАВКЕ МОЕЙ КНОПКИ ОТПРАВИТЬ, ОПРЕДЕЛЕННОЙ ВЫШЕ
    // НО ПОЧЕМУ ДВАЖДЫ?

    возврат $rightStructureValues;
  }

...
...
}
Рейтинг:4
флаг cn

В Ajax-запросе форма перестраивается с нуля. Здесь часто спрашивали, почему метод сборки формы вызывается два или даже три раза. Похоже, что объект также перестраивается, когда форма отправляется через Ajax:

Drupal\Core\Entity\EntityForm::afterBuild

  /**
   * Обратный вызов элемента формы #after_build: обновляет сущность с помощью отправленных данных.
   *
   * Обновляет внутренний объект $this->entity отправленными значениями, когда
   * форма перестраивается (например, отправляется через AJAX), поэтому последующие
   * обработка (например, обратные вызовы AJAX) может полагаться на него.
   */
  публичная функция afterBuild (элемент массива $, FormStateInterface $ form_state) {
    // Перестроить объект, если #after_build вызывается как часть формы
    // перестроить, т.е. если мы обрабатываем ввод.
    если ($form_state->isProcessingInput()) {
      $this->entity = $this->buildEntity($element, $form_state);
    }

    вернуть $элемент;
  }

Это вызовет указанный метод в виджетах поля.

Hermann Schwarz avatar
флаг cn
К сожалению, я не смог предотвратить двойной вызов massageFormValues() от имени afterBuild(). Но если можно подробно описать, как это работает, было бы неплохо. Я предоставлю свое собственное решение в качестве ответа.
4uk4 avatar
флаг cn
Нет ничего плохого в том, что этот метод и вся сборка формы вызываются дважды. Основные сопровождающие решили скорее перестроить форму (и сущность в данном случае), чем заполнить базу данных кэшированными формами Ajax, которые никогда не отправляются.
Hermann Schwarz avatar
флаг cn
Я понимаю. Спасибо, 4k4. Я понимаю, это микрооптимизация, которую я делаю :-).
Рейтинг:1
флаг cn

Мой обходной путь/решение. MassageFormValues() по-прежнему вызывается Drupal дважды, но моя логика в нем будет выполнена только один раз, после завершения проверки формы:

MyFieldWidgetClass.php:

class MyFieldWidget расширяет WidgetBase, реализует ContainerFactoryPluginInterface {
...
...

  общедоступная функция massageFormValues ​​(массив $ значений, массив $ форма, FormStateInterface $ form_state) { 

    // massageFormValues() вызывается дважды: при проверке формы и при отправке формы
    // нам нужен только массажFormValues ​​один раз, после того, как $form_state->isValidationComplete() будет TRUE
    если(!$form_state->isValidationComplete()) {
      возвращаться [];
    }
    ...
    ...
    вернуть $rightStructureValues;
  }

...
...
}

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.