diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php index df716e3..5ff1db9 100644 --- a/core/lib/Drupal/Core/Form/FormBuilder.php +++ b/core/lib/Drupal/Core/Form/FormBuilder.php @@ -561,6 +561,23 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) { $unprocessed_form = $form; $form = $this->doBuildForm($form_id, $form, $form_state); + // Allow an ajax callback while the form is operating in GET mode. + // For example when using HOOK_form_views_exposed_form_alter. + if ($form_state->isMethodType('get')) { + $triggered = $this->requestStack->getCurrentRequest()->request->get('_triggering_element_name'); + if ($triggered && isset($form[$triggered]) && isset($form[$triggered]['#ajax'])) { + $form_state->setTriggeringElement($form[$triggered]); + throw new FormAjaxException($form, $form_state); + } + //Allow an ajax callback on Page views. + if (isset($form['secondary'])) { + if ($triggered && isset($form['secondary'][$triggered]) && isset($form['secondary'][$triggered]['#ajax'])) { + $form_state->setTriggeringElement($form['secondary'][$triggered]); + throw new FormAjaxException($form, $form_state); + } + } + } + // Only process the input if we have a correct form submission. if ($form_state->isProcessingInput()) { // Form values for programmed form submissions typically do not include a diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php index 9ee3704..91a3fe1 100644 --- a/core/modules/views/src/ViewExecutable.php +++ b/core/modules/views/src/ViewExecutable.php @@ -689,7 +689,8 @@ public function getExposedInput() { // Ensure that we can call the method at any point in time. $this->initDisplay(); - $this->exposed_input = \Drupal::request()->query->all(); + $request = \Drupal::request(); + $this->exposed_input = $request->isMethod('get') ? $request->query->all() : $request->request->all(); // unset items that are definitely not our input: foreach (['page', 'q'] as $key) { if (isset($this->exposed_input[$key])) { diff --git a/core/modules/views/tests/src/FunctionalJavascript/ExposedFilterAJAXTest.php b/core/modules/views/tests/src/FunctionalJavascript/ExposedFilterAJAXTest.php index 0ab4277..8b804d7 100644 --- a/core/modules/views/tests/src/FunctionalJavascript/ExposedFilterAJAXTest.php +++ b/core/modules/views/tests/src/FunctionalJavascript/ExposedFilterAJAXTest.php @@ -19,7 +19,13 @@ class ExposedFilterAJAXTest extends WebDriverTestBase { /** * {@inheritdoc} */ - public static $modules = ['node', 'views', 'views_test_modal']; + public static $modules = ['node', 'views', 'views_test_modal', 'views_test_config']; + + /** + * {@inheritdoc} + */ + public static $testViews = ['test_content_ajax']; + /** * {@inheritdoc} @@ -146,4 +152,36 @@ public function testExposedFiltersInModal() { $this->assertNotContains('Page Two', $html); } + /** + * Tests if AJAX events can be attached to the exposed filter form. + */ + public function testExposedFilterAjaxCallback() { + ViewTestData::createTestViews(self::class, ['views_test_config']); + + // Attach an AJAX event to all 'title' fields in the exposed filter form. + \Drupal::service('module_installer')->install(['views_test_exposed_filter']); + $this->resetAll(); + $this->rebuildContainer(); + $this->container->get('module_handler')->reload(); + + // Create a user privileged enough to view content. + $user = $this->drupalCreateUser([ + 'administer site configuration', + 'access content', + 'access content overview', + ]); + $this->drupalLogin($user); + + $this->drupalGet('test-content-ajax'); + + $page = $this->getSession()->getPage(); + $this->assertSession()->pageTextContains('Default prefix'); + + $page->fillField('title', 'value'); + $this->assertSession()->assertWaitOnAjaxRequest(); + + $this->assertSession()->pageTextContains('Callback called.'); + } + } +