I'm not sure if this is a bug or I'm just doing something wrong so I've tagged it as support for now.

I'm trying to make a custom views filter plugin that uses ajax in the form. It's a multi-vocabulary term select - the user selects a vocabulary then selects a term from that vocabulary from an ajax-populated list.

However, I'm encountering several bizarre issues while trying to set it up. If I provide the ajax callback as [$this, 'updateTerms'] it gives me this ajax error in preview:

A fatal error occurred: Recursion detected

Ajax never even runs in the full view. In this case the widget is not rendered at all and the error occurs even on the first load of the widget.

If I provide the ajax callback as either '::updateTerms' or 'Drupal\de_vocabulary_level_views_filter\Plugin\views\filter::updateTerms' it gives me this error in the views preview:

A fatal error occurred: The specified #ajax callback is empty or not callable.

and, inexplicably, this error on the full view:

An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (8 MB) that this server supports.

This issue occurs even on a fresh minimal install of Drupal 8 core with no extra modules or configuration besides enabling taxonomy, views, views_ui and the custom module itself and adding the filter to a view.

The form is pretty simple and works outside of views.

The form is provided in the valueForm function (though I've had the same results inside buildExposedForm) which is overridden like so:

  /**
   * {@inheritdoc}
   */
  protected function valueForm(&$form, FormStateInterface $form_state) {
    $vocabularies = $this->vocabularyStorage->loadMultiple();
    $vocab_options = array();

    foreach ($vocabularies as $voc) {
      $vocab_options[$voc->id()] = $voc->label();
    }

    $form['value'] = [
      'vocab' => [
        '#title' => $this->t('Vocabulary'),
        '#type' => 'select',
        '#options' => $vocab_options,
        '#empty_option' => $this->t('- Any -'),
        '#empty_value' => NULL,
        '#default_value' => !empty($form_state->get('vocab')) ? $form_state->get('vocab') : NULL,
        '#ajax' => [
          'event' => 'change',
          'callback' => 'Drupal\de_vocabulary_level_views_filter\Plugin\views\filter::updateTerms',
          'wrapper' => 'de-vocabulary-level-views-filter-terms-wrapper'
        ],
      ],
      'de_vocabulary_level_views_filter' => [
        '#title' => $this->t('Term'),
        '#type' => 'select',
        '#empty_option' => $this->t('- Any -'),
        '#empty_value' => NULL,
        '#default_value' => !empty($form_state->get('term')) ? $form_state->get('term') : NULL,
      ],
      '#prefix' => '<div id="de-vocabulary-level-views-filter-terms-wrapper">',
      '#suffix' => '</div>',
    ];

    if (!empty($form_state->getValue('vocab'))) {
      $term_query = $this->entityQuery->get('taxonomy_term')
        ->condition('status', 1)
        ->condition('vid', $form_state->getValue('vocab'));
      $term_query_result = $term_query->execute();
      $terms = $this->termStorage->loadMultiple($term_query_result);
      $term_options = [];
      foreach ($terms as $term) {
        $term_options[$term->id()] = $term->label();
      }
      $form['value']['de_vocabulary_level_views_filter']['#options'] = $term_options;
    }
  }

There's a small ajax callback:

  public function updateTerms(&$form, FormStateInterface $form_state) {
    return $form[$this->options['expose']['identifier']];
  }

Currently it reloads a section of the form from the base of the filter form but the same results occur treating it as if it was just the bit from valueForm.

Comments

Dylan Donkersgoed created an issue. See original summary.

lendude’s picture

Project: Views (for Drupal 7) » Drupal core
Version: 8.x-3.x-dev » 8.3.x-dev
Component: Miscellaneous » ajax system

Moving to the core Views queue.

robert ngo’s picture

Subscribe

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

superlolo95’s picture

Same issue I have with a settings form for a view area using drupal 8.3.7.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

steven buteneers’s picture

Experiencing this problem as well in the latest 8.6-dev when trying use #ajax in buildOptionsForm() for a @ViewsRow plugin.

Andrei Tyuhai’s picture

Andrei Tyuhai’s picture

Version: 8.6.x-dev » 8.8.x-dev
yonailo’s picture

Same problem as #8 here.

I haved tried patch #77 from #2842525 and it does not solve this issue.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

gonssal’s picture

I've been hit by this same issue when implementing a custom complex filter that needs AJAX functionality.

The main problem here is that when you use [$this, 'ajaxCallback'] or '::ajaxCallback', it's important to understand that when the form processes the callback, $this or the :: shortcut will be the form's class and not your filter plugin's class, hence the "The specified #ajax callback is empty or not callable" error. The function is in your filter's plugin class, not on the views exposed form's one.

I really needed to do this so I found a way. First you probably have to apply patch #83 (at the time of writing) from #2842525: Ajax attached to Views exposed filter form does not trigger callbacks

Then you have to set your AJAX callback like this in your filter plugin class:

'callback' => [self::class, 'ajaxCallback'],

Your ajaxCallback function should be static or you will get a warning.

Now the trick to get your filter plugin's class instance is to pass it through the form's state. I'm doing it like such:

$form_state->set(self::class . '_instance', $this);

And then in your ajaxCallback, you do...

$instance = $form_state->get(self::class . '_instance');

... and you use that instead of $this.

thetwentyseven’s picture

I have the same problem. The latest patch #2842525: Ajax attached to Views exposed filter form does not trigger callbacks mentioned by @gonssal does not apply correctly for me with the Drupal version: 8.9.19

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

cilefen’s picture

Status: Active » Closed (outdated)

#13 seems to be a full answer. Thank you for that.