2

My module has a custom Views style plugin. In the style settings form, I want to implement an ajax callback, such as described here: https://www.drupal.org/docs/8/api/javascript-api/ajax-forms

However, I haven't had any luck. I can get a spinning effect, but nothing happens afterward. Here's an example of what I've tried:

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;  

  public function TestCallback(array $form, FormStateInterface $form_state) {
    $ajax_response = new AjaxResponse();
    $text = 'Text to see if this is working';
    $ajax_response->addCommand(new HtmlCommand('#foo', $text));

    return $ajax_response;
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);

    $form['test'] = [
      '#title' => t('TEST!'),
      '#type' => 'select',
      '#options' => [
        '' => t('None'),
        'foo' => t('Bar'),
      ],
      '#ajax' => [
        'event' => 'change',
        'callback' => '::TestCallback',
    // having the line below uncommented seems to help        
    //'url' => views_ui_build_form_url($form_state),
      ],
      '#prefix' => '<div id="foo"></div>',
      '#default_value' => '',
    ];
  }

If I uncomment the commented 'url', I get this error:

Uncaught TypeError: Cannot read property 'settings' of undefined
at resetSize (<anonymous>:34:32)
at later (debounce.js?v=8.6.3:20)

If I keep it commented, I get:

Failed to load resource: the server responded with a status of 500 () 
/admin/structure/views/ajax/display/view_name/page_1/style_options? 
_wrapper_format=drupal_ajax&ajax_form=1&_wrapper_format=drupal_ajax:1
Uncaught Drupal.AjaxError
ajax.js?v=8.6.3:500

What's missing and/or incorrect?

  • I believe it could have something to do about a missing form ID for the style plugin. – andileco Jan 22 '19 at 17:09
2
+50

From what I understand seeing the AJAX docs, I think you're not supposed to return an AjaxResponse object. You're supposed to return a renderable array from the Ajax callback.

Sample Code

public function buildOptionsForm(&$form, FormStateInterface $form_state) {
  parent::buildOptionsForm($form, $form_state);
  $form['test'] = [
    '#title' => t('TEST!'),
    '#type' => 'select',
    '#options' => [
      '' => t('None'),
      'foo' => t('Bar'),
    ],
    '#ajax' => [
      'event' => 'change',
      'wrapper' => 'ajax-output-container',
      // Since views style options forms are complex, they're built by
      // Drupal in a different way. To bypass this problem we need to
      // provide the full path to the Ajax callback.
      'callback' => __CLASS__ . '::testCallback',
    ],
    '#prefix' => '<div id="ajax-output-container"></div>',
    '#default_value' => '',
  ];
}

/**
 * This is the AJAX callback.
 *
 * It generates the output for the AJAX request. The output REPLACES
 * the "wrapper" you define in #ajax.
 */
public function testCallback(array $form, FormStateInterface $form_state) {
  // This element will replace the DIV#foo you have in your #prefix.
  $elem = [
    '#type' => 'markup',
    '#markup' => '<div id="ajax-output-container">Is it not working!></div>',
  ];
  return $elem;
}

Debugging

  • Make sure that on page load, you're getting a div with the correct ID in your field prefix. You can put some default text in the prefix so that you can see it on page load?
  • If HTML tags are being stripped from your #prefix markup for some reason, then try injecting a separate item in the form with #markup.
| improve this answer | |
  • Thanks for including the sample code. I'm still getting the same errors, unfortunately. – andileco Jan 23 '19 at 21:37
  • Can you share the entire error message backtrace? Can you see in the network tab of the dev console to check what output Drupal is returning for the AJAX request? – Jigarius Jan 23 '19 at 22:07
  • OK, I'm getting this in the DB log: Symfony\Component\HttpKernel\Exception\HttpException: The specified #ajax callback is empty or not callable. in Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse() (line 67 of /app/web/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php). – andileco Jan 23 '19 at 22:19
  • If I click on the URL in the network tab, I also see this: [{ "command": "insert", "method": "prepend", "selector": null, "data": "\n\n\u003C!-- THEME DEBUG ... BEGIN OUTPUT from \u0027core\/themes\/classy\/templates\/misc\/status-messages.html.twig\u0027 --... Error message\u003C\/h2\u003E\n An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (100 MB) that this server supports.\n \u003C\/div\u003E\n \u003C\/div\u003E\n \n\u003C!-- END OUTPUT ...", "settings": null }] – andileco Jan 23 '19 at 22:24
  • 1
    The addition of "'callback' => CLASS . '::testCallback'," makes it work! – andileco Jan 28 '19 at 1:00
0

$route_name = "views_ui.form_{$form_key}"; might be the problem.

Try to print somewhere this result under buildOptionsForm function and see if it is the problem: views_ui_build_form_url($form_state)->toString();

If You keep it commented, error happens because their is no url nor '#wrapper' which is needed for ajax.

Here you can investigate this error deeper: https://api.drupal.org/api/drupal/core%21modules%21views_ui%21admin.inc/function/views_ui_build_form_url/8.2.x

| improve this answer | |
0

I think you maybe experiencing an issue related to this Drupal core issue. See this issue comment and this one about implementing a work-around.

| improve this answer | |

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.