Ajax is broken in forms built within an Ajax callback

Created on 4 January 2018, almost 7 years ago
Updated 22 August 2023, about 1 year ago

This could be a bug, or it could be working as designed and my methodology is wrong.

Summary:
I have a form with a checkbox. The checkbox has an ajax callback. The ajax callback prepares a separate second form, and opens it in a modal. The problem is the second form's ajax is broken.

Here is a basic setup:

First Form buildForm:

public function buildForm(array $form, FormStateInterface $form_state) {
    $form['my_checkbox'] = array(
      '#type' => 'checkbox',
      '#title' => 'my checkbox',
      '#ajax' => array(
        'callback' => array($this, 'clickMyCheckbox'),
        'event' => 'change',
        'progress' => 'throbber',
      ),
    );
    return $form;
  }

First Form "clickMyCheckbox" AJAX Callback:

public static function clickMyCheckbox(array &$form, FormStateInterface $form_state) {
    $second_form = \Drupal::formBuilder()->getForm('Drupal\my_project\Form\SecondForm');
    $response = new AjaxResponse();
    $response->addCommand(new OpenModalDialogCommand('Second Form', $second_form, array('width' => '600')));
    return $response;
}

Second Form buildForm:

public function buildForm(array $form, FormStateInterface $form_state) {
    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
    $form['my_actions'] = array('#type' => 'actions');
    $form['my_actions']['cancel'] = array(
      '#type' => 'button',
      '#value' => t('Cancel'),
      '#ajax' => array(
        'callback' => array($this, 'cancelForm'),
        'event' => 'click',
        'progress' => FALSE,
      ),
    );
    $form['my_actions']['submit'] = array(
      '#type' => 'button',
      '#value' => t('Confirm'),
      '#ajax' => array(
        'callback' => array($this, 'submitForm'),
        'event' => 'click',
        'progress' => FALSE,
      ),
    );
    return $form;
  }

Second Form "cancelForm" AJAX Callback:

public function cancelForm(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response->addCommand(new CloseModalDialogCommand());
    return $response;
  }

In the above example, clicking the checkbox opens the second form in a modal, however, the Cancel button doesn't close the modal; none of the AJAX works.

From what I can tell working with this issue, it seems the second form is built using data from and being wrapped in the first form, instead of being a standalone form. The ajaxTrustedUrl being passed also includes the _wrapper_format=html query, when it should be ajax. If I build the second form on its own, the AJAX works, so I know it has to be due to building the form in the AJAX callback for another form.

Am I going about this the correct way? Is there a way to unset/reset these settings when building the second form? I've found two issues which appear to be somewhat related:

https://www.drupal.org/project/drupal/issues/2504709 🐛 Prevent _wrapper_format and ajax_form parameters from bleeding through to generated URLs Active
https://www.drupal.org/project/drupal/issues/2504115

🐛 Bug report
Status

Active

Version

11.0 🔥

Component
Ajax 

Last updated about 8 hours ago

Created by

🇺🇸United States joegl

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024