2

I created a custom module which contains a Class Form. When I submit my form, I redirect the user to the form page. During the submission, I need to save a form_state variable to re-use it after the user is redirected to the form.

So, from my submit method, I save my variable (with "$form_state->set(...)" ) and I add "$form_state->setRebuild()".

All works perfectly. Now, I want preserve my variable AND empty some field's form. I don't want to preserve values of all fields of my form after the user has been redirected.

I tried this :

// From my buildForm
// ...
$form['test'] = [
  '#type' => 'textfield',
  '#title' => "test",
];
$form['submit'] = [
  '#type' => 'submit',
  '#value' => t('Submit'),
];
//...
// I check if my var exist, if yes, that means the user has submited the form and has been redirected to the form
if($form_state->has('results') && $form_state->get('results')) {
  $form_state->setValueForElement($form['test'],"0");
}
return $form;

But I have this error when I use the setValueForElement method :

The website encountered an unexpected error. Please try again later. TypeError: Argument 1 passed to Drupal\Component\Utility\NestedArray::keyExists() must be of the type array, string given, called in /(...)/core/lib/Drupal/Core/Form/FormBuilder.php on line 1296 in Drupal\Component\Utility\NestedArray::keyExists() (line 259 of core/lib/Drupal/Component/Utility/NestedArray.php).

I don't understand where my mistake is, use the setValueForElement maybe not the better way?

Edit (after Ismail Cherri's answer)

This is my new code : ("$form['#parents'] = array();" added)

// From my buildForm
// ...
$form['test'] = [
  '#parents' => [],
  '#type' => 'textfield',
  '#title' => "test",
];
$form['submit'] = [
  '#type' => 'submit',
  '#value' => t('Submit'),
];
//...
// I check if my var exist, if yes, that means the user has submited the form and has been redirected to the form
if($form_state->has('results') && $form_state->get('results')) {
  $form_state->setValueForElement($form['test'],"0");
}
return $form;

I keep the same error when I submit my form...

The website encountered an unexpected error. Please try again later. TypeError: Argument 1 passed to Drupal\Component\Utility\NestedArray::keyExists() must be of the type array, string given, called in /(...)/core/lib/Drupal/Core/Form/FormBuilder.php on line 1296 in Drupal\Component\Utility\NestedArray::keyExists() (line 259 of core/lib/Drupal/Component/Utility/NestedArray.php).

3
  • You've to use #parents to Form element and not to $form, i.e. test field in above form, e.g. $form['test']['#parents'] = array('status');
    – Yogesh
    Oct 11, 2016 at 14:59
  • I tested with "$form['test']['#parents'] = array('status')" or "$form['test']['#parents'] = array(1)" or "$form['test']['#parents'] = array()" (instead "$form['#parents'] = array();")..but I keep always the same error :/ Oct 11, 2016 at 19:54
  • ma be the error is somewhere else . Because the code seems perfect and fine Oct 14, 2016 at 11:18

3 Answers 3

2

Can you please try adding this to your buildForm() method:

$form['#parents'] = array();

According to documentation: FormStateInterface::setValueForElement You need to pass an array() and set the parents array for the form element.
Hope this helps.

UPDATE
After revisiting the documentation, can you try this code:

$form_state->setValueForElement($form_state->getValue('test'),"0");
2
  • I have already the same error..I update my initial post ! Oct 10, 2016 at 23:12
  • With your update, I get this error... "The website encountered an unexpected error. Please try again later. TypeError: Argument 1 passed to Drupal\Core\Form\FormState::setValueForElement() must be of the type array, string given, called in /var/www/.../modules/custom/.../src/Form/...Form.php on line 129 in Drupal\Core\Form\FormState->setValueForElement() (line 79 of core/lib/Drupal/Core/Form/FormStateValuesTrait.php)." :/ Oct 15, 2016 at 13:14
1

The error you are getting, is because $form['test'] doesn't have a #parents attribute. So to fix the error you have right now, you would need to do this:

$form['test'] = [
  '#parents' => [],
  ...
];

That said, going about it this way is very messy, and I would suggest you use some alternate solutions instead.

Sneaky reset

Instead of trying to manipulate the form into thinking the user hasn't giving a value for test, you can simply rename it:

if ($form_state->has('results') && $form_state->get('results')) {
  // Copy form test to clear old submitted values.
  $form['test_1'] = $form['test'];
  // Assign the default value you want.
  $form['test_1']['#default_value'] = '';
  // Hide form test.
  $form['test']['#access'] = FALSE;
}

This is pretty simple/clever, but would require your validation/submit handler to take this into account.

2 forms / FULL reset.

Another solution would be to have multiple forms, or completely reset the form, and instead save the submitted data in cookies, sessions or something similar which is persistent. Then you could set default values you wanted to presave from the session or cookie. This could potentially be a bit messy, as you would need to clear the session as it otherwise would save the data for a long time, handle TTL etc.

1
  • Thanks you for your detailed answer :) (+1) If I try your first code, I get errors I described above (Argument 1 passed to Drupal\Component\Utility\NestedArray::keyExists()). Youre solution 2 works I thinks but its an ugly way I think :/ If the user submit the form several times consecutively, it will become brothel x) Your last solution is a lot complex for this simple problem :/ I think Ill take time for drupal 8 hard debugging.. Oct 17, 2016 at 19:08
0

No need to add parents, you can check if form has been submitted in a validate function:

In your form:

$form['test'] = [
  '#type' => 'textfield',
  '#title' => "test",
  '#element_validate' => array(array(get_class($this), 'validateTestField')),
];

then add the validate function:

  public static function validateTestField($element, FormStateInterface $form_state) {
    if($form_state->isSubmitted() && !empty($form_state->getValue('results'))) {
      $form_state->setValueForElement($element, "0");
      $element['#default_value'] = "0";
    }
  }
3
  • Thank you for your answer ! but I build an array from the "submitForm" method and I want clear some field depends of this array :) Oct 17, 2016 at 19:48
  • try $form_state->getValue('results'), it should be there if you added it to $form_state
    – oknate
    Oct 17, 2016 at 19:55
  • The problem is : I submit the Form. The validateTestField is called. After, the array 'results' is build during the submitForm method. The user is redirected to the form ('results' is defined) but the 'validateTestField isn't called then this fields isn't cleared... I need clear this field when the user is redirected to the form after submit it. Oct 17, 2016 at 20:20

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.