Score:0

AJAX on Form Details

us flag

I have a lot of API calls in a form, so in order to not call everything on load, I only want to load it when the user opens the details element.

But I am having trouble adding #ajax to the element. I can see a spinner and that it calls buildForm(), but it is not triggering the callback method. When I wrap the ajax part inside e.g. an checkbox, it works. Thus, I come to the conclusion that it is something with the details element.

How can I create an ajax callback, when the user opens the details element?

Non-working example with ajax on details:

public function buildForm(array $form, FormStateInterface $form_state) {
  [...]
  return [
    '#type' => 'details',
    '#title' => $title,
    '#open' => FALSE,
    '#ajax' => [
      'callback' => [$this, 'openAccordion'],
      'event' => 'click',
    ],
  ];
}

public function openAccordion(array $form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  return $response;
}

Working example where ajax is on a button (just an example):

return [
  '#type' => 'details',
  '#title' => $title,
  '#open' => FALSE,
  'widget' => [
    '#type' => 'button',
    '#value' => 'Load',
    '#ajax' => [
      'callback' => [$this, 'openAccordion'],
      'event' => 'click',
    ],
  ],
];
Jaypan avatar
de flag
Is this code in your ajax callback?
id flag
Can we see a the full implementation minus irrelevant fields please?
NicklasF avatar
us flag
I added a working example. As seen in the code, the only difference is that ajax is not on `details`.
Jaypan avatar
de flag
How are you determining it is not triggering the callback? Is there a message in the Drupal log? Are there any messages in the JS console?
NicklasF avatar
us flag
Im using xdebug and have set a breakpoint. No console logs and no Drupal logs. Also because of xdebug, I can see it reaches a breakpoint in buildForm after click but it is not hitting the callback method.
Score:2
de flag

I am suspecting you cannot attach #ajax to non-input elements. As the display element does not take an input, it likely doesn't trigger #ajax. You can do the following as a fix.

  1. Create a library:

    details_element_ajax:
      css:
        theme:
          css/details_element_ajax.css
      js:
        js/details_element_ajax.js
    dependencies:
      - core/once
      - core/jquery
    
    
  2. Add a details element, and a submit button that triggers the ajax, and attach the library

    $form['details'] = [
      '#open' => FALSE,
      '#markup' => '',
      '#attached' => ['library' => 'examplemodule/details_element_ajax',
    ];
    
    $form['hidden_submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('load_details),
      '#ajax' => [
        'callback' => [$this, 'openAccordion'],
        'event' => 'click',
      ],
    ];
    
  3. Hide the submit button in the CSS file:

    #edit_hidden_submit {
      display:none;
    }
    
  4. In the JS file, when the details element is opened, click the hidden submit button to trigger the ajax:

    Drupal.behaviors.displayElementAjax = {
      attach: function(context) {
        const elements = $(context).find('#details_element_ajax').once('myfeature');
        elements.each(function () {
          $(this).click(function() {
            $("#edit_hidden_submit').click();
          });
        });
      }
    };
    
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.