I have a custom form where I have a search field and button. After the users clicks the button, I load some items based on what they've entered into the search field.
The problem that I'm having is that when my form is being rebuilt after the AJAX callback is fired, there are no values in $form_state->values
so I can't access them with $form_state->getValue()
. However, I do see the input in $form_state->input
. When I view the documentation for $form_state->getUserInput()
, it states:
These are raw and unvalidated, so should not be used without a thorough understanding of security implications. In almost all cases, code should use self::getValues() and self::getValue() exclusively.
That makes sense to me, and I'd love to, but the values aren't there. However, I did notice that if I remove the container from my example below, so that all of my fields are directly at the root of the form array, the values are in $form_state->values
in ::buildSearchResults()
after AJAX rebuild. Why is that the case? What am I missing here?
My code:
public function buildForm(array $form, FormStateInterface $form_state) {
// Note that I see the same issue even when setting #tree to FALSE.
$form['container'] = [
'#type' => 'container',
'#tree' => TRUE,
];
$form['container']['search_field'] = [
'#type' => 'textfield',
'#title' => $this->t('Search field'),
];
$form['container']['ajax_button'] = [
'#type' => 'button',
'#value' => t('Search'),
'#name' => 'ajax_button',
'#limit_validation_errors' => [],
'#ajax' => [
'callback' => [static::class, 'myCallbackFunction'],
'wrapper' => 'search_results',
'event' => 'click',
],
];
$form['container']['search_results'] = [
'#type' => 'container',
'#attributes' => [
'id' => 'search_results',
],
'items' => $this->buildSearchResults($form_state),
];
return $form;
}
public static function myCallbackFunction(array &$form, FormStateInterface $form_state): array {
// I think I need this here?
$form_state->setRebuild();
return $form['container']['search_results'];
}
public function buildSearchResults(FormStateInterface $form_state) {
// This is always empty at this stage. :(
// In fact, the values array is totally empty.
// Though I can see the values in $form_state->input.
// And, as I stated earlier, if I drop the container from my
// form and put all fields at the root of the form, the values
// property is not empty and I can access my field values there.
$search_text = $form_state->getValue(['container', 'search_field'], '');
return views_embed_view('view_id', 'display_id', $search_text);
}
Update 1:
@4uk4's answer inspired some more testing. It seems that even if I remove the AJAX functionality so that the button triggers my form's submitForm()
method, the values are still missing from the $form_state->values
array. After retesting this example code, I can no longer reproduce my issue at all.
Update 2:
I believe the behavior @4uk4 was describing was causing me to see some false positives here when testing the example code. When I tested with my real code, I'd see my issue always, on first AJAX rebuild, with no triggering element set and on all subsequent rebuilds. However, I think I was only ever testing this example code with to the first rebuild, the rebuild with no triggering element and no values were processed - I'd see no values in $form_state->values
(what I was expecting, given my tests with my actual code), but if I had ever tested long enough for the second rebuild, the actual AJAX submission, I'd have seen the field values in $form_state->values
.