7

Given:

  • I am using Drupal 8.
  • I have a custom "add form" of the custom entity type.
  • Form has an ajax submission.

Problem:

  • When I submit form all the values remain in fields.

Expected:

  • Form fields should be cleared after submission.

Form source code:

<?php

namespace Drupal\mymodule\Form;

use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Form\FormStateInterface;

/**
 * Form controller for the add/edit entity forms.
 */
class MymoduleForm extends ContentEntityForm {

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildForm($form, $form_state);

    $form['#prefix'] = "<div id=\"{$this->getFormId()}-wrapper\">";
    $form['#suffix'] = '</div>';

    $form['actions']['submit']['#ajax'] = [
      'wrapper' => $this->getFormId() . '-wrapper',
      'callback' => array($this, 'ajaxRebuildCallback'),
      'effect' => 'fade',
    ];

    return $form;
  }

  /**
   * Callback for ajax form submission.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return array
   *   The rebuilt form.
   */
  public function ajaxRebuildCallback(array $form, FormStateInterface $form_state) {
    drupal_set_message(t('Entity was successfully created'));

    // @todo Clear form values.
    //$form_state->setRebuild(TRUE);
    //$form_state->setValues([]);
    /*$entity = \Drupal::entityTypeManager()->getStorage('liveblog_post')->create([]);
    $form_object = \Drupal::entityTypeManager()
      ->getFormObject('liveblog_post', 'add')
      ->setEntity($entity);*/
    //$new_form_state = new FormState();
    //$form = \Drupal::formBuilder()->rebuildForm($this->getFormId(), $form_state);

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state) {
    $entity = $this->getEntity();
    $entity->save();
  }

}

P.S. you can find my attempts in the ajaxRebuildCallback() method.

1
  • I have the very same problem ! Still searching a solution.
    – Gaius
    Nov 11, 2016 at 21:39

3 Answers 3

11

@Berdir's answer helped me to figure out the solution. We should indeed clear the user input, but we can not simply just say $form_state->setUserInput([]), because there are some system values, that should stay(e.g. form_id, form_token, _triggering_element_name, etc.).

I have created a custom method for it:

  /**
   * Clears form input.
   *
   * @param array $form
   *   The form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  protected function clearFormInput(array $form, FormStateInterface $form_state) {
    // Replace the form entity with an empty instance.
    $this->entity = $this->entityTypeManager->getStorage('my_entity_type')->create([]);
    // 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]);
      }
    }
    $form_state->setUserInput($input);
    // Rebuild the form state values.
    $form_state->setRebuild();
    $form_state->setStorage([]);
  }

I am calling $this->clearFormInput($form, $form_state); in the MymoduleForm::save() method(the very last step of the submission).

Update 08.03.2021

If you have a created date field in the entity form, it will be cached in $form_state after submission. You will have to reset it's value for the entities. You can do it by overriding the \Drupal\Core\Entity\EntityForm::processForm:

 /**
   * {@inheritdoc}
   *
   * Resets default values for a new entity.
   */
  public function processForm($element, FormStateInterface $form_state, $form) {
    $element = parent::processForm($element, $form_state, $form);

    if ($this->entity->isNew()) {
      $this->entity->set('created', $this->time->getRequestTime());
    }

    return $element;
  }
0
9

You are looking for https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Form%21FormStateInterface.php/function/FormStateInterface%3A%3AsetUserInput/8.2.x.

The values are the validated input, for setting the default values, the form system respects the original user input, which you can change with the method above.

However, for entity forms, it is a bit more complicated. $this->entity is a reference to the entity, you will still have that and it will fallback to that. What you probably need to do is create a new entity in save, assign it to $this->entity, then empty user input and $form_state->setRebuild(). That should then rebuild the form with a new and empty entity.

2
  • 1
    thank you for the answer. I tried the $form_state->setUserInput() as well. But I get an error with a strange message: An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (32 MB) that this server supports.. P.S. I am executing it in the MymoduleForm::save() method. Unsettling the entity and $form_state->setRebuild(); did not help. Also tried at the ::ajaxRebuildCallback().
    – milkovsky
    Nov 14, 2016 at 11:10
  • After 5 years I have discovered a bug in this approach. Creating a new entity sets the created date with the current time, which gets cached in the $form_state. As result that the next saved entity will have a created date of the previous entity.
    – milkovsky
    Mar 8, 2021 at 15:21
1

In your ajax callback

$response->addCommand(new InvokeCommand('#edit-new-note', 'val', ['']));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.