Should you encounter an error like
The specified #ajax callback is empty or not callable form
Then presumably you're using something like this:
'#ajax' => [
'callback' => '::updateFormAjaxCallback',
'wrapper' => 'layout-wrapper',
],
or an external class callback:
'#ajax' => [
'callback' => '\Drupal\homebox\Form\HomeboxPersonalizeForm::updateFormAjaxCallback',
'wrapper' => 'layout-wrapper',
],
As you could guess from the :: notation, the called method needs to be static!
So this won't work:
public function updateFormAjaxCallback(array &$form, FormStateInterface $form_state): array {
// Replace the whole layout:
return $form['layout_wrapper'];
}
But instead, this will work (see the static):
public static function updateFormAjaxCallback(array &$form, FormStateInterface $form_state): array {
// Replace the whole layout:
return $form['layout_wrapper'];
}
Non-static calls with $this
In contrast to that, if you're using
'#ajax' => [
'callback' => [$this, 'updateFormAjaxCallback'],
'wrapper' => 'layout-wrapper',
],
here the non-static call will work (as it's being called on the object / instance)!
Other potential reasons
Thanks to @Jaypan:
- The class that the ajax callback lives in must implement Drupal\Core\Security\TrustedCallbackInterface
- The class must also implement the trustedCallbacks() function, returning an array with the name of your callback function
Mind array vs. string
Another risky thing with the callback is array vs. string notation!
When using the shorthand, ensure you're returning a string, not an array:
Doesn't work:
'callback' => ['::updateFormAjaxCallback'],
Works:
'callback' => '::updateFormAjaxCallback',
These are really hard to find bugs ;)