diff --git a/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php b/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php index 7d1c4b75a415339a2ae0bc9f694a425228b79502..44ff641c9327a4c5b206dde8bc0bc742e1babd37 100644 --- a/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php +++ b/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php @@ -81,6 +81,15 @@ public function buildResponse(Request $request, array $form, FormStateInterface $response = $result; } else { + // At this point we know callback returned a render element. If the + // element is part of the group (#group is set on it) it won't be rendered + // unless we remove #group from it. This is caused by + // \Drupal\Core\Render\Element\RenderElement::preRenderGroup(), which + // prevents all members of groups from being rendered directly. + if (!empty($result['#group'])) { + unset($result['#group']); + } + /** @var \Drupal\Core\Ajax\AjaxResponse $response */ $response = $this->ajaxRenderer->renderResponse($result, $request, $this->routeMatch); } diff --git a/core/modules/system/src/Tests/Ajax/AjaxInGroupTest.php b/core/modules/system/src/Tests/Ajax/AjaxInGroupTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9732d28a630f10e1afc40898c44833ec7cddcd1f --- /dev/null +++ b/core/modules/system/src/Tests/Ajax/AjaxInGroupTest.php @@ -0,0 +1,38 @@ +<?php + +/** + * @file + * Contains \Drupal\system\Tests\Ajax\AjaxInGroupTest. + */ + +namespace Drupal\system\Tests\Ajax; + +use Drupal\Core\Ajax\DataCommand; + +/** + * Tests that form elements in groups work correctly with AJAX. + * + * @group Ajax + */ +class AjaxInGroupTest extends AjaxTestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalLogin($this->drupalCreateUser(array('access content'))); + } + + /** + * Submits forms with select and checkbox elements via Ajax. + */ + function testSimpleAjaxFormValue() { + $this->drupalGet('/ajax_forms_test_get_form'); + $this->assertText('Test group'); + $this->assertText('AJAX checkbox in a group'); + + $this->drupalPostAjaxForm(NULL, ['checkbox_in_group' => TRUE], 'checkbox_in_group'); + $this->assertText('Test group'); + $this->assertText('AJAX checkbox in a group'); + $this->assertText('AJAX checkbox in a nested group'); + $this->assertText('Another AJAX checkbox in a nested group'); + } +} diff --git a/core/modules/system/tests/modules/ajax_forms_test/src/Callbacks.php b/core/modules/system/tests/modules/ajax_forms_test/src/Callbacks.php index 7722fc9f5a87786409457b7f620d68fb49021410..c4c29f8c87b9b72dd6fee057f145d4b21734837f 100644 --- a/core/modules/system/tests/modules/ajax_forms_test/src/Callbacks.php +++ b/core/modules/system/tests/modules/ajax_forms_test/src/Callbacks.php @@ -36,4 +36,12 @@ function checkboxCallback($form, FormStateInterface $form_state) { $response->addCommand(new DataCommand('#ajax_checkbox_value', 'form_state_value_select', (int) $form_state->getValue('checkbox'))); return $response; } + + /** + * Ajax callback triggered by the checkbox in a #group. + */ + function checkboxGroupCallback($form, FormStateInterface $form_state) { + return $form['checkbox_in_group_wrapper']; + } + } diff --git a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestSimpleForm.php b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestSimpleForm.php index 2fcfd1f334af7232ad6b8547a5f0fff3d9b2d5eb..2c974883e83c63d709809f1e46306c6f6f64a823 100644 --- a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestSimpleForm.php +++ b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestSimpleForm.php @@ -72,6 +72,48 @@ public function buildForm(array $form, FormStateInterface $form_state) { ); } + $form['test_group'] = [ + '#type' => 'details', + '#title' => $this->t('Test group'), + '#open' => TRUE, + ]; + + // Test ajax element in a #group. + $form['checkbox_in_group_wrapper'] = [ + '#type' => 'container', + '#attributes' => ['id' => 'checkbox-wrapper'], + '#group' => 'test_group', + 'checkbox_in_group' => [ + '#type' => 'checkbox', + '#title' => $this->t('AJAX checkbox in a group'), + '#ajax' => [ + 'callback' => [$object, 'checkboxGroupCallback'], + 'wrapper' => 'checkbox-wrapper', + ], + ], + 'nested_group' => [ + '#type' => 'details', + '#title' => $this->t('Nested group'), + '#open' => TRUE, + ], + 'checkbox_in_nested' => [ + '#type' => 'checkbox', + '#group' => 'nested_group', + '#title' => $this->t('AJAX checkbox in a nested group'), + '#ajax' => [ + 'callback' => [$object, 'checkboxGroupCallback'], + 'wrapper' => 'checkbox-wrapper', + ], + ], + ]; + + $form['another_checkbox_in_nested'] = [ + '#type' => 'checkbox', + '#group' => 'nested_group', + '#title' => $this->t('Another AJAX checkbox in a nested group'), + ]; + + return $form; }