I'm working on a block form that needs to update certain elements in the form based on what the user selects with certain elements. I've defined the internal class method and it's getting called correctly; however, it can't access the values stored in the form from the $form_state.

For example, when I call $form_state->getValue('filter_field'), it returns an empty value, even though it has been set on the page. I suspect that this may be due to the fact that I'm setting the callback like so: 'callback' => [get_class($this), 'updateWidgetAjax'], and in the final comment in the API, it says to do it like this: 'callback' => '::updateWidgetAjax'. However, when I try this, I get the The specified #ajax callback is empty or not callable. error. I tried following the tutorial on the API page as well as here, yet neither of them worked properly, spouting out the same error as before. I also went through this checklist, but most of the items don't apply.

Additionally, and this is just something annoying but related, if I don't mark updateWidgetAjax as static I get the following message in my log: Deprecated function: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Drupal\global_filter\Plugin\Block\FilterBlock::updateWidgetAjax() should not be called statically, which I suspect will be resolved with fixing the above issue.

In short, how do I get the form values in my Ajax callback?

The element calling the Ajax:

$form['filter_field'] = [
  '#type' => 'select',
  '#name' => 'filter_field',
  '#title' => t('Select field to get the filter value from.'),
  '#options' => self::getAvailableFields(),
  '#empty_option' => t('Select a field'),
  '#ajax' => [
    'callback' => [get_class($this), 'updateWidgetAjax'],
    'event' => 'change',
    'wrapper' => 'default-value-ajax-wrapper',
    //The wrapper is elsewhere on the form
  '#required' => TRUE,

The Ajax callback function:

public function updateWidgetAjax(array &$form, FormStateInterface $form_state) {
  $widget = '';
  $multichoice = FALSE;

  switch ($form_state->getValue('widget_type')) {
    //code that sets $widget
  //Return a render array
  $render = [
    '#type' => $widget,
    '#name' => 'default_value',
    '#title' => t('Default value'),
    '#description' => t('Select the default value for this filter. Leave blank for none.'),
    '#options' => self::getOptions($widget, $form_state->getValue('filter_field')),
    '#required' => TRUE,
  return $render;

EDIT: I forgot to mention that the form is defined with a blockForm, since I'm trying to create new blocks with this. I'm following the Drupal documentation found here. I think this might be a big part of the issue.

  • I don't think you need to use get_class. Just pass $this and ::method.
    – Kevin
    Sep 28, 2016 at 23:41

1 Answer 1


I have tried this on my local it works . So you can achieve the form values by using this . Please try this

    $form['filter_field'] = [
      '#title' => $this->t('Filter'),
      '#type' => 'select',
      '#options' => ['drupal7' => 'Drupal7', 'drupal8' => 'Drupal8'],
      '#empty_option' => $this->t('-select'),
      '#ajax' => [
        'callback' => '::updateWidgetAjax',
        'wrapper' => 'default-value-ajax-wrapper',
    $form['widget_type'] = [
      '#title' => $this->t('Widget Type'),
      '#type' => 'select',
      '#options' => ['pdf' => 'Pdf', 'ppt' => 'PPT'],
      '#empty_option' => $this->t('-select'),

    $form['wrapper'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'default-value-ajax-wrapper'],

    return $form;

//Ajax callback 
  public function updateWidgetAjax(array &$form, FormStateInterface $form_state) {
   $widget = $form_state->getValue('widget_type');
    print_r($widget); //Print the value of the field
  • I forgot to mention that this is in a blockForm function. The edit contains a little more info; I wonder if that has anything to do with the problems I'm running into.
    – Greenstack
    Sep 29, 2016 at 17:21
  • i have updated the code just try this and get back to me' Sep 30, 2016 at 6:22

Your Answer

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

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