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).

  • 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 '16 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 :/ – user2137454 Oct 11 '16 at 19:54
  • ma be the error is somewhere else . Because the code seems perfect and fine – Shreya Shetty Oct 14 '16 at 11:18
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");
  • I have already the same error..I update my initial post ! – user2137454 Oct 10 '16 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)." :/ – user2137454 Oct 15 '16 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.

  • 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.. – user2137454 Oct 17 '16 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";
    }
  }
  • Thank you for your answer ! but I build an array from the "submitForm" method and I want clear some field depends of this array :) – user2137454 Oct 17 '16 at 19:48
  • try $form_state->getValue('results'), it should be there if you added it to $form_state – oknate Oct 17 '16 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. – user2137454 Oct 17 '16 at 20:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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