Problem/Motivation

When an exposed filter is placed twice on the same page it gets the same html identifier.
Every instance of this block / form needs to have their own unique id attribute.
This is needed for some contributed projects, but it's also not allowed to be duplicated according to the w3c rules.

The id attribute specifies its element's unique identifier (ID). The value must be unique amongst all the IDs in the element's home subtree and must contain at least one character. The value must not contain any space characters.

https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#the-id-attribute

Proposed resolution

Use Html::getUniqueId() to generate the ID.

Remaining tasks

Review, fix tests.

User interface changes

None

Release notes snippet

CommentFileSizeAuthor
#147 2894747-147.patch12.53 KBfernly
#146 2894747-145.patch13.38 KBabdelrahman amer
#132 2894747-10.5.x-mr-10945--132.patch11.36 KBsonfd
#127 drupal-2894747-ajax-duplicate-exposed-forms-10.3.x-127.patch68.3 KBniels de ruijter
#126 drupal-2894747-ajax-duplicate-exposed-forms-11.x-126.diff11.72 KBcodebymikey
#126 drupal-2894747-ajax-duplicate-exposed-forms-10.1.x-126.diff11.73 KBcodebymikey
#125 2894747-10.2-125.patch11.86 KBeugene bocharov
#120 2894747-10.2.3-120.patch11.86 KBpeachez
#119 2894747-10.2.3-119.patch11.77 KBpeachez
#116 2894747-10.2.3-116.patch11.77 KBpeachez
#114 2894747-114.patch15.1 KBmuath khraisat
#113 2894747-11.x-MR4767-8497343f.diff12.3 KBrecrit
#113 2894747-10.1.x-MR5595-c96a7b79.diff12.3 KBrecrit
#111 Screenshot 2023-12-16 at 3.59.01 AM.png163.66 KBveronicaseveryn
#104 2894747-nr-bot.txt90 bytesneeds-review-queue-bot
#102 2894747-11.x-MR4767-b8a1ad05.diff11.78 KBrecrit
#102 2894747-10.1.x-MR5595-4d25940c.diff11.78 KBrecrit
#101 interdiff-2894747-98-93.txt1.37 KBrecrit
#98 drupal-d11_hardcoded_exposed_form_id_breaks_ajax-2894747-98.patch11.39 KBmatthijs
#98 drupal-d10_hardcoded_exposed_form_id_breaks_ajax-2894747-98.patch11.39 KBmatthijs
#93 2894747-D11-MR4767-7312f749--20230913-3.diff11.03 KBrecrit
#93 2894747-D10-MR4386-26695c46--20230913-3.diff11.07 KBrecrit
#92 2894747-D10-MR4386-6ac0afe9--20230913.diff12.88 KBrecrit
#92 2894747-D11-MR4767-5d67bf5e--20230913.diff12.84 KBrecrit
#89 2894747-MR4386-e07684fd--20230913.diff13.83 KBrecrit
#86 2894747-86.patch13.26 KB_utsavsharma
#86 interdiff_84-86.txt569 bytes_utsavsharma
#84 2894747_views_hardcodes-exposed-filter-id-10.0.x-84.diff13.83 KBcodebymikey
#79 2894747-79.patch15.1 KBcristian100
#78 2894747-78.patch12.68 KBsahil.goyal
#77 2894747-77.patch14.74 KBmojiferous
#74 2894747-74.patch11.33 KB_utsavsharma
#74 interdiff_73-74.txt1.47 KB_utsavsharma
#73 2894747-73.patch11.34 KBameymudras
#72 2894747-72.patch14.74 KB_utsavsharma
#72 interdiff_71-72.txt1.8 KB_utsavsharma
#71 2894747-65.patch15.16 KBprpaul
#64 interdiff_63-64.txt815 bytesranjith_kumar_k_u
#64 2894747-64.patch12.43 KBranjith_kumar_k_u
#63 core-duplicated-exposed-form-2894747-63.patch12.47 KBabarrio
#63 interdiff-62-63.patch1.36 KBabarrio
#62 2894747-62-reroll-53.patch12.39 KBbartlangelaan
#53 randomize_exposed_filter_block_form_ID-2894747-53-d8.patch11.99 KBveronicaseveryn
#51 randomize_exposed_filter_block_form_ID-2894747-51-d8.patch12.28 KBveronicaseveryn
#49 2894747-49.patch11.44 KBrajandro
#43 interdiff_38-43.txt724 bytesravi.shankar
#43 2894747-43.patch11.41 KBravi.shankar
#38 2894747-38.patch11.44 KBmohrerao
#34 2894747-34.patch10.44 KBlendude
#29 2894747-29.patch10.44 KBlendude
#29 2894747-29-TEST-ONLY.patch3.1 KBlendude
#26 2894747-26.patch7.34 KBlendude
#26 2894747-26-TEST-ONLY.patch2.08 KBlendude
#24 interdiff.2894747.19-24.txt1.28 KBsuper_romeo
#24 2894747-24.drupal.Views-exposed-form-double-html-ids.patch5.26 KBsuper_romeo
#23 8.7.x-2894747-23-views-exposed-form-double-html-ids.patch5.51 KBmilindk
#22 8.7.x-2894747-22-views-exposed-form-double-html-ids.patch5.44 KBmilindk
#20 2894747-18-views-exposed-form-double-html-ids.patch6.38 KBmilindk
#19 2894747-18-views-exposed-form-double-html-ids.patch4.76 KBmilindk
#18 2894747-18-views-exposed-form-double-html-ids.patch4.75 KBmilindk
#5 Views-8.3.x-exposed_form_double_ids_fix-2894747-5.patch1.87 KBbasvanderheijden
#2 Views-8.3.x-exposed_form_double_ids_fix-2894747-2.patch1.12 KBmvwensen

Issue fork drupal-2894747

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mvwensen created an issue. See original summary.

mvwensen’s picture

Status: Needs work » Needs review
StatusFileSize
new1.12 KB

Patch attached, please review and provide feedback if necessary! (Or fix it ;).)

Status: Needs review » Needs work

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

basvanderheijden’s picture

Status: Needs work » Needs review
StatusFileSize
new1.87 KB

By making the ID's unique, the selector (javascript) doesn't work anymore, because it's still referencing the static selector.
In the attached patch, I've resolved the issue by changing the selector from the unique ID (which cannot be derived) to a class name.

Status: Needs review » Needs work
mpotter’s picture

Unfortunately this doesn't seem to work with Ajax enabled-views. It causes a new page to be reloaded as if Ajax was disabled.

Also, the "id" of the input field is still the same. So Ajax-enabled views with exposed filter forms get confused because of the duplicate ids. So it's not just the form-id that needs to be changed.

mpotter’s picture

The problem on my site seems to be that this patch adds the class to the wrapping div and not the actual form element. So the JS selector needs to be something more like this:

this.$exposed_form = $('.views-exposed-form-' + settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-') + ' form');

however, even with that change, and changing the input id in my code, having two exposed forms for the same view on the same page using Ajax doesn't seem to ever finish the ajax callback. So at least in my case something more complicated is going on.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

gertjanmeire’s picture

Are there any updates to resolve this issue?
This currently breaks accessibility checks on forms using better exposed filters...

semanthis’s picture

This is quite a annoying problem, having to exposed filters of the same view on the same page is not very unusual. Ajax on such pages is important to prevent page-jumping. Why can't the id of the input be constructed by [view-name]-[display]. I'm not so into the ajax-thing of views, so I can't offer a fix, but I would be very happy if someone could take care of that problem...

d.fisher’s picture

Just came across this when running lighthouse on a new D8 site using views/better exposed filters and the same exposed filter block being used twice on a page. Following for updates.

biigniick’s picture

I also have a site with this issue. Anyone find a solution?

cilefen’s picture

There is a small family of related issues. Some could be duplicates.

bès’s picture

The usage of Html::getUniqueId() is a good idea but it will not work until we have the issue #1831560: Remove Html::resetSeenIds() call during form processing fixed.

milindk’s picture

Version: 8.6.x-dev » 8.8.x-dev
milindk’s picture

Rerolling patch as 8.8.x is released, and solve the test cases issue.

milindk’s picture

StatusFileSize
new4.76 KB

There was a small mistake while fetching the id, attaching corrected patch.

milindk’s picture

StatusFileSize
new6.38 KB

Fix test case issue

milindk’s picture

Status: Needs work » Needs review
milindk’s picture

Attaching patch for 8.7.x as MediaOverviewTest.php not present in 8.7.x and its introduced in 8.8.x

milindk’s picture

StatusFileSize
new5.51 KB

My bad Attaching patch for 8.7.x above patch fails because of mistakely format-patch with 8.8.x.

super_romeo’s picture

if in attachment inherit exposed filters == TRUE then $view->exposed_widgets == [] and:

Notice: Undefined index: #id in views_views_pre_render() (line 60 of core/modules/views/views.module).

lendude’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests
+++ b/core/modules/views/js/ajax_view.es6.js
@@ -99,12 +99,7 @@
+    this.$exposed_form = $('form#' + settings.view_html_id);

diff --git a/core/modules/views/js/ajax_view.js b/core/modules/views/js/ajax_view.js
index 95a803d7fe..531a2d9406 100644

+++ b/core/modules/views/js/ajax_view.js
@@ -65,7 +65,7 @@
+    this.$exposed_form = $('form#' + settings.view_html_id);

If we are refactoring this, wouldn't it make more sense to refactor away from using the HTML ID in the first place? Can't we set an data attribute that just uses the existing 'view_dom_id' setting?

Also, this needs tests.

lendude’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new2.08 KB
new7.34 KB

Here is a test for this, simply placing the block twice.

The fix in #24 doesn't fix this.

Test only patch is also the interdiff

lendude’s picture

So per #16, this has a hard dependency on #1831560: Remove Html::resetSeenIds() call during form processing which is currently RTBC. That fixes the test-only patch in #26, so this needs additional coverage to show that Views ajax needs a little extra love to get this to work.

Status: Needs review » Needs work

The last submitted patch, 26: 2894747-26.patch, failed testing. View results

lendude’s picture

Status: Needs work » Needs review
StatusFileSize
new3.1 KB
new10.44 KB

More tests, full JS test this time.

This new test will fail even with the patch from #1831560: Remove Html::resetSeenIds() call during form processing applied, so when that gets committed we will still have a test only patch to show that Views needs additional fixes.

Expected red/green:
- with #1831560 committed, test only and fix patch in #26 will go green
- with #1831560 committed, test only in #29 will stay red, but fix will be green (well it was locally, so fingers crossed)

lendude’s picture

Title: Views exposed form double html ids » Views hardcodes exposed filter block form ID's which breaks AJAX when the same form is shown multiple times on one page
Issue summary: View changes

Updated the title to make it more specific to the bug we are trying to fix once #1831560: Remove Html::resetSeenIds() call during form processing lands and updated the IS a bit.

The last submitted patch, 29: 2894747-29-TEST-ONLY.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 29: 2894747-29.patch, failed testing. View results

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

lendude’s picture

Status: Needs work » Needs review
StatusFileSize
new10.44 KB

Here is a reroll of #29

Status: Needs review » Needs work

The last submitted patch, 34: 2894747-34.patch, failed testing. View results

krzysztof domański’s picture

1) Drupal\Tests\views\Kernel\Plugin\ExposedFormRenderTest::testExposedFormRender
Expected form ID found.
Failed asserting that false is true.

The 'test_exposed_form_buttons' view configuration has an exposed filter. An additional exposed filter is added in the $exposed_form->renderExposedForm();. We have two such forms, which is the reason for test failure.

public function testExposedFormRender() {
  $view = Views::getView('test_exposed_form_buttons');
  $this->executeView($view);
  $exposed_form = $view->display_handler->getPlugin('exposed_form');
  $output = $exposed_form->renderExposedForm();
  $this->setRawContent(\Drupal::service('renderer')->renderRoot($output));

      $this->assertFieldByXpath('//form/@id', Html::cleanCssIdentifier('views-exposed-form-' . $view->storage->id() . '-' . $view->current_display'), 'Expected form ID found.');

Now the second block has the id 'views-exposed-form-test-exposed-form-buttons-default--2' .

--- a/core/modules/views/tests/src/Kernel/Plugin/ExposedFormRenderTest.php
+++ b/core/modules/views/tests/src/Kernel/Plugin/ExposedFormRenderTest.php
@@ -43,7 +43,7 @@ public function testExposedFormRender() {
     $output = $exposed_form->renderExposedForm();
     $this->setRawContent(\Drupal::service('renderer')->renderRoot($output));
 
-    $this->assertFieldByXpath('//form/@id', Html::cleanCssIdentifier('views-exposed-form-' . $view->storage->id() . '-' . $view->current_display), 'Expected form ID found.');
+    $this->assertFieldByXpath('//form/@id', Html::cleanCssIdentifier('views-exposed-form-' . $view->storage->id() . '-' . $view->current_display . '--2'), 'Expected form ID found.');
krzysztof domański’s picture

Issue tags: +Needs reroll
mohrerao’s picture

StatusFileSize
new11.44 KB

Rerolled parch in #34 for 9.1.x. Also updated changes suggested in #37.2
Couldnt add an interdiff as there was change in code on
from
this.$exposed_form = $('form#views-exposed-form-' + settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-'));
to
this.$exposed_form = $("form#views-exposed-form-".concat(settings.view_name.replace(/_/g, '-'), "-").concat(settings.view_display_id.replace(/_/g, '-')));

mohrerao’s picture

Status: Needs work » Needs review
krzysztof domański’s picture

Status: Needs review » Needs work
Issue tags: -Needs reroll

@mohrerao thanks!

Minor, there is no reason to replace assertCount with assertEqual here.

--- a/core/modules/views/tests/src/Kernel/ViewElementTest.php
+++ b/core/modules/views/tests/src/Kernel/ViewElementTest.php
@@ -126,7 +126,7 @@ public function testViewElementEmbed() {
     $this->setRawContent($renderer->renderRoot($render));
 
     // Ensure that the exposed form is rendered.
-    $this->assertCount(1, $this->xpath('//form[@class="views-exposed-form"]'));
+    $this->assertEqual(1, count($this->xpath('//form[@class="views-exposed-form views-exposed-form-test-view-embed-embed-2"]')));
mohrerao’s picture

@Krzysztof, Thanks. I believe both would yield same result. However this is from the patch in #34.

krzysztof domański’s picture

The result is the same, but the assertCount is more appropriate here.
See #3128814: Replace assert* involving count() and an equality operator with assertCount() or #3128573: [meta] Replace assertions with more appropriate ones.

-    $this->assertCount(1, $this->xpath('//form[@class="views-exposed-form"]'));
+    $this->assertCount(1, $this->xpath('//form[@class="views-exposed-form views-exposed-form-test-view-embed-embed-2"]'));
ravi.shankar’s picture

Status: Needs work » Needs review
StatusFileSize
new11.41 KB
new724 bytes

Here I have tried to address comment #42.

nikro’s picture

+++ b/core/modules/views/js/ajax_view.js
@@ -64,8 +64,7 @@
+    this.$exposed_form = $('form#' + settings.view_html_id);
     this.$exposed_form.once('exposed-form').each($.proxy(this.attachExposedFormAjax, this));

I'm a bit confused by this line. If we rename the ID of the 2nd form and apply the ajax functionality by # - this will only allow 1st form update the view via Ajax, while 2nd makes non-Ajax submission.

I didn't follow the issue from the beginning, however changing this into this (taking in account that we have a class with exactly same id):

+    this.$exposed_form = $('form.' + settings.view_html_id);

Makes both forms submit nicely.

krzysztof domański’s picture

Version: 8.9.x-dev » 9.1.x-dev
Status: Needs review » Needs work
+  /**
+   * Asserts that each HTML ID is used for just a single element on the page.
+   */
+  protected function assertNoDuplicateIds() {

Instead of adding an additional method assertNoDuplicateIds(), we can use the new assert pageContainsNoDuplicateId(). See The pageContainsNoDuplicateId assert was added to WebAssert.

krzysztof domański’s picture

If we rename the ID of the 2nd form and apply the ajax functionality by # - this will only allow 1st form update the view via Ajax, while 2nd makes non-Ajax submission.

@Nikro I have not tested manually yet, but I see there is a test coverage for this.

+   * Test that AJAX works with two exposed blocks on the same page.
+   */
+  public function testExposedFilterWithDoubleExposedBlock() {
rajandro’s picture

Assigned: Unassigned » rajandro

Working on this

lendude’s picture

If we rename the ID of the 2nd form and apply the ajax functionality by # - this will only allow 1st form update the view via Ajax, while 2nd makes non-Ajax submission.

@Krzysztof Domański Actually, we don't have test coverage for this, only that a submission is done, not that an AJAX submission is done. So we should absolutely add a check that the submissions are done using AJAX and not by page reload. I haven't checked manually either, but we should add it to the automated test either way.

rajandro’s picture

Assigned: rajandro » Unassigned
Status: Needs work » Needs review
StatusFileSize
new11.44 KB

Hi,

Since this is moved to 9.1.x, hence it requires to reroll. I am attaching the rerolled patch for 9.1.x

Though, I have a concern as we have some changes in 9.1.x
Please find the 8.9.x patch difference:

- this.$exposedform = $('form#views-exposed-form-' + settings.view_name.replace(//g, '-') + '-' + settings.viewdisplay_id.replace(//g, '-'));
+ this.$exposed_form = $('form#' + settings.view_html_id);

Same changes I have done for 9.1.x

- this.$exposedform = $("form#views-exposed-form-".concat(settings.view_name.replace(//g, '-'), "-").concat(settings.viewdisplay_id.replace(//g, '-')));
+ this.$exposed_form = $('form#' + settings.view_html_id);

A Javascript expert's opinion will be helpful to determine the use of concat is required here or not.

Thanks!

veronicaseveryn’s picture

Tested patch #43 and had two instances of the same exposed form on the same page (the blocks are placed on the same page in different regions via blocks UI ). I am on Drupal 8.9.4. The view is AJAX enabled. To be 100% sure nothing else affects it, also tested with default Seven theme and without any BEF module. Same result.

FIRST use case: Exposed Form on the AJAX view is set to "Exposed form in block":YES

  1. Submitting the form caused page refresh, instead of AJAX update..
  2. The form IDs did differ after all, but they are still View ID-DisplayID based, e.g. <form action="/find-a-doctor" method="get" id="views-exposed-form-search-index-doctors-find-doc--3" accept-charset="UTF-8">
  3. No additional classes were observed on the forms
  4. Submitting the form caused page refresh, instead of AJAX update, as changes in AJAX selector are not applied

SECOND use case: Exposed Form on the AJAX view is set to "Exposed form in block":NO

  1. So, I only have one exposed form now - its ID is still View ID-DisplayID based, though it did get additional classes this time around.
    <form class="views-exposed-form views-exposed-form-search-index-doctors-find-doc" data-drupal-selector="views-exposed-form-search-index-doctors-find-doc" action="/find-a-doctor" method="get" id="views-exposed-form-search-index-doctors-find-doc" accept-charset="UTF-8" _lpchecked="1">
  2. Submitting the form did trigger AJAX submission

So, the form didn't even get View Dom_ID identifier as ID or any additional classes.. This happens in the case when . To be clear also, . - maybe I am missing some other fixes?

Did anyone test it manually and was actually successful?

I have looked through the code and had a few minor changes suggested (which were tested and worked in my case - I am not sure how previous patches were tested previously).

veronicaseveryn’s picture

This is a patch for Drupal 8.9.4 version.

I modified AJAX JS to get applied to the forms based on this selector:

this.$exposed_form = $('form[id^="views-exposed-form-' + settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-') + '"]');

Also, when I had two AJAX exposed form blocks on the same page, I was getting multiple AJAX progress indicators attached to the document body , and only 1 of them was cleaned up with old code. So, I also added a modification to ajax.js as follow, to find all instances and remove on success:

    if (this.progress.element) {
      $('.' + $(this.progress.element).attr('class').replace(/\s/g, '.')).remove();
    }

I didn't update any TESTS in the patch though..

With this patch I don't get duplicate form IDs any more, AJAX submission works on each form instance, and no hanging throbbers remain.

Status: Needs review » Needs work
veronicaseveryn’s picture

Status: Needs work » Needs review
StatusFileSize
new11.99 KB

Accidentally committed additional stuff in #51 that shouldn't be there.. cleaning up the patch

Status: Needs review » Needs work
lendude’s picture

Issue tags: +Needs tests

@veronicaSeveryn thanks for looking at this, but:

+++ b/core/misc/ajax.js
@@ -426,7 +426,7 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
-      $(this.progress.element).remove();
+      $('.' + $(this.progress.element).attr('class').replace(/\s/g, '.')).remove();

This is very much out of scope for this issue, and when you make changes to a patch please add an interdiff, right now it is hard to see what else was changed, but we can say that it broke some tests.

The exposed form in block case is something we do need to add coverage for (and possibly a fix), and we need to expand the coverage we are adding for the AJAX filtering to make sure they are actually using AJAX and not triggering a page reload.

So tagging with 'Needs tests' again.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

leisurman’s picture

Using Drupal 9.2.9. Patch #49 works for me. Thank you

bartlangelaan’s picture

StatusFileSize
new12.39 KB

This is a simple reroll of #53, which should be compatible with 9.3.x.

abarrio’s picture

Status: Needs work » Needs review
StatusFileSize
new1.36 KB
new12.47 KB

Hi all,

patch on #62 fixes the problem about progress icon but not the submit event. I have been working on it and found that in the ajax_views.js there is some point in the creation of ajax_view objects that code search exposed forms with this expression:

this.$exposed_form = $("form[id^=\"views-exposed-form-".concat(settings.view_name.replace(/_/g, '-'), "-").concat(settings.view_display_id.replace(/_/g, '-'), "\"]"));

This expression returns all forms so this is why all submit are called at same time.
I changed the load of it to search only in view dom not in complete dom.

this.$view.find("form[id^=\"views-exposed-form-".concat(settings.view_name.replace(/_/g, '-'), "-").concat(settings.view_display_id.replace(/_/g, '-'), "\"]"));

I upload diff and interdiff.

ranjith_kumar_k_u’s picture

StatusFileSize
new12.43 KB
new815 bytes

Status: Needs review » Needs work

The last submitted patch, 64: 2894747-64.patch, failed testing. View results

leisurman’s picture

Using Drupal 9.3.0 Patch #49 no longer can be applied

leisurman’s picture

Has this been rolled into Drupal 9.3? The patch did not apply. I don't have the duplicate exposed form id error anymore. The id of the 2 forms on the page are now different. One has 2 dashes appended to the id name.

leisurman’s picture

Update. The error came back. I still see the duplicate exposed form id error

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

prpaul’s picture

StatusFileSize
new15.16 KB

This patch works for me with drupal 9.5.1

_utsavsharma’s picture

StatusFileSize
new1.8 KB
new14.74 KB

Tried to fix CCF for #71.
Please review.

ameymudras’s picture

Status: Needs work » Needs review
StatusFileSize
new11.34 KB

Creating a patch for 10.1.x

_utsavsharma’s picture

StatusFileSize
new1.47 KB
new11.33 KB

Tried to fix CCF for #73.
Please review.

Status: Needs review » Needs work

The last submitted patch, 74: 2894747-74.patch, failed testing. View results

super_romeo’s picture

Patch #72 raise exception on every ajax call

jquery.min.js?v=3.6.3:formatted:572 Uncaught Error: Syntax error, unrecognized expression: '.' + $(this.progress.element).attr('class').replace(//g, '.')
    at se.error (jquery.min.js?v=3.6.3:formatted:572:19)
    at se.tokenize (jquery.min.js?v=3.6.3:formatted:996:42)
    at se.select (jquery.min.js?v=3.6.3:formatted:1051:75)
    at Function.se [as find] (jquery.min.js?v=3.6.3:formatted:301:20)
    at E.fn.init.find (jquery.min.js?v=3.6.3:formatted:1165:19)
    at new E.fn.init (jquery.min.js?v=3.6.3:formatted:1186:50)
    at E (jquery.min.js?v=3.6.3:formatted:55:16)
    at Drupal.Ajax.success (ajax.js?v=9.5.2-dev:390:7)
    at Object.success (ajax.js?v=9.5.2-dev:215:37)
    at c (jquery.min.js?v=3.6.3:formatted:1325:33)
se.error @ jquery.min.js?v=3.6.3:formatted:572
se.tokenize @ jquery.min.js?v=3.6.3:formatted:996
se.select @ jquery.min.js?v=3.6.3:formatted:1051
se @ jquery.min.js?v=3.6.3:formatted:301
find @ jquery.min.js?v=3.6.3:formatted:1165
E.fn.init @ jquery.min.js?v=3.6.3:formatted:1186
E @ jquery.min.js?v=3.6.3:formatted:55
Drupal.Ajax.success @ ajax.js?v=9.5.2-dev:390
success @ ajax.js?v=9.5.2-dev:215
c @ jquery.min.js?v=3.6.3:formatted:1325
fireWith @ jquery.min.js?v=3.6.3:formatted:1378
l @ jquery.min.js?v=3.6.3:formatted:3777
(anonymous) @ jquery.min.js?v=3.6.3:formatted:3904
load (async)
send @ jquery.min.js?v=3.6.3:formatted:3912
ajax @ jquery.min.js?v=3.6.3:formatted:3684
Drupal.Ajax.eventResponse @ ajax.js?v=9.5.2-dev:304
(anonymous) @ ajax.js?v=9.5.2-dev:255
dispatch @ jquery.min.js?v=3.6.3:formatted:2034
y.handle @ jquery.min.js?v=3.6.3:formatted:1966
mojiferous’s picture

StatusFileSize
new14.74 KB

There seemed to be a regression in the regex in patch #72, I have updated it so it applies for 9.5.x and does not break

sahil.goyal’s picture

StatusFileSize
new12.68 KB

update patch for the corresponding version D10.1 there. sorry i couldn't able to create interdiff due to some system issue i guess.

cristian100’s picture

StatusFileSize
new15.1 KB

Updated patch for version D9.5.9.

heikkiy’s picture

We have been using this patch in our projects for a long time but we also noticed that there were some weird problems with the views exposed filters. In our case it was scrolling the wrong view to focus after the exposed form was submitted.

We debugged the issue and noticed that it was not enough that the view had a unique ID in it but we needed to also make the drupal-data-selector unique.

In our case we basically created an input preprocess and checked if the input is a exposed views filter submit and then changed the drupal-data-selector to be unique:

$variables['attributes']['data-drupal-selector'] = $variables['attributes']['data-drupal-selector'] . '-' . strtolower($unique_str);

We have a common function for the unique id but this might be worth checking in this issue also.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

codebymikey made their first commit to this issue’s fork.

codebymikey’s picture

Status: Needs work » Needs review
StatusFileSize
new13.83 KB

Rerolled for 10.x branch and attached a static patch.

smustgrave’s picture

Status: Needs review » Needs work

For the CC Failure. Also MR should be updated for 11.x please.

_utsavsharma’s picture

StatusFileSize
new569 bytes
new13.26 KB

Fixed CC as mentioned in #85.

recrit’s picture

The view_html_id set in drupalSettings is not used anywhere. Is this still needed? If it is cruft left over from the original approach, then it should be removed.

vflirt’s picture

There is issue with the patch from #86:
`.${$(this.progress.element).attr('class').replace(/\s/g, '.')},`,
this produces selector with extra comma at the end such as :
.ajax-progress.ajax-progress-throbber,
and this leads to
Uncaught Error: Syntax error, unrecognized expression: .ajax-progress.ajax-progress-throbber,
that breaks every ajax call with progress

recrit’s picture

StatusFileSize
new13.83 KB

@vflirt The concatenation has been fixed in the MR. Attached is a static patch of the D10 MR 4386 at commit e07684fd.
Pending Work: open MR for D11.x

recrit’s picture

hiding old patches to eliminate any confusion

recrit’s picture

StatusFileSize
new12.84 KB
new12.88 KB

Added D11 MR 4767
Updated both MRs with a fix for erroneous removals of "++" in core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php from original patch.

Attached static patches for both D10 and D11.

recrit’s picture

StatusFileSize
new11.07 KB
new11.03 KB

Attaching static patches for the MRs with passing tests.

recrit’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work

Noticed this was adding additional classes to the block also but IS mentions just using a unique ID.
Example I turned the content view filters into a block placed on the /admin/content page
Before
views-exposed-form block block-views block-views-exposed-filter-blockcontent-page-1
After patch
views-exposed-form views-exposed-form-content-page-1 block block-views block-views-exposed-filter-blockcontent-page-1

recrit’s picture

The extra class is being added to the $form in "core/modules/views/src/Form/ViewsExposedForm.php:" (see below). Then views takes all of the $form classes and puts them on the wrapping block DIV instead of the FORM elemtn.

Patched "core/modules/views/src/Form/ViewsExposedForm.php:"

$form['#attributes']['class'][] = $clean_form_id;

All of the form queries in the patch are using the new "starts with" ID selector so this new class may not be needed.

akalam’s picture

I have tested some of the patches attached in this issue (#84, #86 and #93) and all of them work with ajax disabled. Having 2 exposed forms with ajax enabled avoid the exposed form block from being replaced (both don't get replaced). Without the patch at least one of the blocks get replaced but with the patch none of them.

matthijs’s picture

Might be related to my custom code, but I noticed that with #93 the ajax event handler is bound multiple times. This happens because this.$exposed_form contains all forms. I fixed this by replacing it with a constant and added the form as argument to the attachExposedFormAjax function.

recrit changed the visibility of the branch 2894747-views-hardcodes-exposed to hidden.

recrit’s picture

@Matthijs
(1) This issue has started with issue branches so please do not submit patches.
(2) If you do submit a patch, you should provide an interdiff.txt showing what you have changed since the previous patch. I attahced an interdiff for reference: interdiff-2894747-98-93.txt.

recrit’s picture

@Matthijs
I applied the intent of your changes to the MR's for 11.x (MR 4767) and 10.1.x (MR 5595).

(1) I kept this.$exposed_form being set. Some other JS or contribute modules may expect it to be set. Example: entity_browser contrib module.
(2) Calling Drupal.views.ajaxView.prototype.attachExposedFormAjax with a single element will not work since it is expecting to setup all forms and build the array this.exposedFormAjax = [];. I handled this by directly calling this.attachExposedFormAjax(); to setup all forms, and moving the once() check to the actual submit buttons instead of the exposed form in order to ensure that the actual buttons never have more than one ajax instance.

Attached are static patches for any composer builds.

recrit’s picture

Status: Needs work » Needs review
needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

recrit’s picture

Status: Needs work » Needs review

I rebased the 11.x MR

matthijs’s picture

@recrit Thanks. It didn't want to change to the MR because I wasn't sure if the issue was caused by my custom code and existed for others as well.

recrit’s picture

@Matthijs Thanks, makes sense. Please try the latest changes to the MR to verify that it fixes your issue as well.

smustgrave changed the visibility of the branch 11.x to hidden.

smustgrave changed the visibility of the branch 10.1.x to hidden.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests +Needs Review Queue Initiative

Removing tests tag as they've been added

There was 1 failure:
1) Drupal\Tests\views\Kernel\ViewElementTest::testViewElementEmbed
Failed asserting that actual size 0 matches expected size 1.
/builds/issue/drupal-2894747/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:121
/builds/issue/drupal-2894747/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:55
/builds/issue/drupal-2894747/core/modules/views/tests/src/Kernel/ViewElementTest.php:129
/builds/issue/drupal-2894747/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
FAILURES!
Tests: 3, Assertions: 18, Failures: 1.

The fix of using unique ID makes 100% sense just trying to think of a scenario where that could cause a breaking change for some, but ultimately any break would mean a site was broken this whole time.

RTBC+1

veronicaseveryn’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new163.66 KB

I have tested MR4767 and it works well on the front-end, but the backend is breaking for Media Library widget.

Once you try to insert a media on a node with Media Library form selection widget and use the text search there to find the media file, it redirects you to "/admin/content/media-widget/image" with 403 status.

Media Library widget

If the MR patch is removed, it works well again.
Not sure whether the AJAX is not being re-attached to the form elements, but with the MR patch applied the pager for Media Library form still works well. It's just this search box that is giving hard time so far.

I have looked at the JS changes in ajax_views.js file and tested reverting this single change in https://git.drupalcode.org/project/drupal/-/merge_requests/5595.patch , and it 1) fixed the issue with Media Library view 2) still works for me on the front-end for other views (AJAX is still applied there, even when there're multiple instances of the same form on a single page):

diff --git a/core/modules/views/js/ajax_view.js b/core/modules/views/js/ajax_view.js
index ac61682c2dd2..c9f45d5d49d4 100644
--- a/core/modules/views/js/ajax_view.js
+++ b/core/modules/views/js/ajax_view.js
@@ -106,9 +106,7 @@
         '-',
       )}-${settings.view_display_id.replace(/_/g, '-')}"]`,
     );
-    once('exposed-form', this.$exposed_form).forEach(
-      $.proxy(this.attachExposedFormAjax, this),
-    );
+    this.attachExposedFormAjax();
 
     // Add the ajax to pagers.
     once(

With the MR patch applied looks like Drupal.views.ajaxView.prototype.attachExposedFormAjax() function was called twice for Media Library view. And while the first time around it did the job to attach AJAX to the form, the second time it was triggered, it didn't go inside the if (once('exposed-form-ajax', this).length) {} condition block, hence, this.exposedFormAjax = []; was reset right above it and remained empty.

smustgrave’s picture

Status: Needs review » Needs work

Good catch! Think we will need additional test coverage for this.

recrit’s picture

@veronicaSeveryn Please test the latest MR patches. I updated the "once()" calls so that it should process as expected.

Attached static patches for any composer builds to use.

Pending: New tests for the media library (if needed).

muath khraisat’s picture

StatusFileSize
new15.1 KB

#79 patch not solving the issue for me after updating the core
The same patch merged with 2968207-40.patch for Drupal 9.5.11

recrit’s picture

peachez’s picture

StatusFileSize
new11.77 KB

Ported 2894747-10.1.x-MR5595-c96a7b79.diff for Drupal 10.2.3

lobodakyrylo’s picture

Patch #116 contains JS syntax error so it doesn't work.

recrit’s picture

peachez’s picture

StatusFileSize
new11.77 KB

Not sure about this dude at 116 and his spelling errors ;)

In all seriousness, thank you to @lobodacyril for the heads up.
Here is the corrected patch

peachez’s picture

StatusFileSize
new11.86 KB

3rd times the charm?

smustgrave’s picture

Just fyi would recommend using MRs as they are faster and have quicker review turnaround.

borisson_’s picture

we're currently working on the new version of facets, in the 3.x branch to make it work only as views exposed filters. This issue blocks us from having feature parity with the 2.x branch.
We plan on using the https://www.drupal.org/project/configurable_views_filter_block module, which would also benefit from this patch.
Adding the contrib project blocker tag to reflect that.

lendude’s picture

The latest patch and the MR patches posted in #113 still break the media library search

recrit’s picture

hiding all 10.2 patches. The 11.x MR and patch in 113 applies cleanly to 10.2.x.

eugene bocharov’s picture

StatusFileSize
new11.86 KB

The patch from #113 is not applicable to 10.2, here's the patch #120 with small but important fix

+    if (once('exposed-form', this.$exposed_form).length) {
+      this.attachExposedFormAjax.bind(this)
+    };

replaced with

+    if (once('exposed-form', this.$exposed_form).length) {
+      this.attachExposedFormAjax();
+    };

otherwise this.attachExposedFormAjax.bind(this) just binds this, but not call the function, so exposed forms don't work by AJAX

codebymikey’s picture

Following on from the feedback from #55, updated the logic so that only the relevant progress elements were removed as a side-effect.

The previous change inadvertently broke integration with Gutenberg 2.8 when editing Media blocks, because it removed the progress bar that already exists in the React lifecycle before it should've causing it to crash.

niels de ruijter’s picture

StatusFileSize
new68.3 KB

Resolved a rejection in core/modules/views/js/ajax_view.js when applying the previous 10.1.x patch to the 10.3.x branch.

sonfd made their first commit to this issue’s fork.

sonfd changed the visibility of the branch 10.5.x to hidden.

sonfd’s picture

Patch in #127 looks like it includes a lot of additional code, hiding.

sonfd’s picture

StatusFileSize
new11.36 KB

Attaching patch file with changes from MR !10945

wannesdr made their first commit to this issue’s fork.

wannesdr’s picture

Assigned: Unassigned » wannesdr

I added a fix for the failing Unit tests in the merge requests for 10.5.x en 11.x (and also on the 10.1.x for consistency).
Let's wait and see if the tests pass now.

borisson_’s picture

Issue summary: View changes

Updated the issue summary.

borisson_’s picture

I reviewed the issue together with @wannesdr at drupal mountain camp. I had some remarks, which I shared in person. Wannes is fixing those as we speak. I think this issue looks good and I will rtbc this when the last things are fixed.

wannesdr’s picture

Good point @borisson_, removed the t function calls.
Thanks for the review & feedback!

borisson_’s picture

Status: Needs work » Reviewed & tested by the community

I have tried to figure out if we are still missing something, but to me it seems like this is complete.

I was wondering if this would break styling on existing websites, but it won't, because the ID would already change when using ajax.

quietone’s picture

Assigned: wannesdr » Unassigned

Updated credit, always more difficult with an older issue an lots of patches.

nod_’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs issue summary update

Thanks so much for updating the credits, I was worried about it :)

Spent time reviewing this and I'm going to need a few things:

  1. The scope seems to have changed a bit, updating title/issue summary would be nice
  2. Steps to reproduce. I could not replicate the problem on the 11.x branch adding 2 exposed filter on the same page with the same ID, both worked with and without the patch. Not sure how to replicate the problem.
  3. From what I understood, the test is checking if we can use form 1 and have some results, and check if form 2 gives the same result, I would expect the results to be different, otherwise how can we be sure that form2 worked?
  4. We should avoid changing Drupal.views.ajaxView.prototype.attachExposedFormAjax because of bunch of themes overwrite it, let's not make it hard on contrib since it seems doable without changing it

mxr576 changed the visibility of the branch 2894747-10.1.x to hidden.

ressa’s picture

Thanks for working on this! In Facets 3, placing AJAX-supported "Facets exposed filters" anywhere else than above the form in a View (the standard position) is not supported, since you have to use https://www.drupal.org/project/configurable_views_filter_block/ to place filters for example in the sidebar regions -- but #3374162: Make it work with AJAX enabled is waiting on this Drupal core issue ...

This could be holding back many users from upgrading to the new and improved Facets 3, so should the Priority for this issue be raised to "Major", to help give it a nudge?

nod_’s picture

Priority: Normal » Major
mortona2k’s picture

Without patch

When exposed filters are not shown in a block, they are all within a form in the exposed variable, in the views-view template.
Exposed sorts are included here as well.

Printing {{ exposed }} twice in the view template causes the bug in #2876197.

Are there any other ways to print the exposed filters/sort in separate forms, without exposing as a block and using Configurable Views Filter Block?

I have been trying things like manipulating the exposed form id:

<div class="view-sort">
  {% set exposed_modified = exposed|merge({'#id': exposed['#id'] ~ '-sort_by'}) %}
  {{ exposed_modified|filter((v,k) => k starts with '#' or k in ['sort_by', 'actions']) }}
<div>
<div class="view-filter">
  {{ exposed }}
<div>

This doesn't work though, the first one refreshes the page.

The workaround I have currently is to create the form elements I need manually, then use custom js to copy those values into the exposed form fields, which will trigger the views ajax. In the case of the search input, I also trigger the form submit button. I have the BEF setting enabled to input automatically, except for text fields.

With patch

Print {{ exposed }} twice, or with some elements removed as above.

The ajax is working without issue.

You can also load the form multiple times into variables, which will give unique ids. This improves the html (no duplicate ids), but didn't fix the issue without the patch.

function mytheme_preprocess_views_view(&$variables) {
  $view = $variables['view'];
  $search_exposed_form = $view->display_handler->getPlugin('exposed_form')->renderExposedForm(FALSE);
  $variables['search_exposed_form'] = $search_exposed_form;
  $sort_exposed_form = $view->display_handler->getPlugin('exposed_form')->renderExposedForm(FALSE);
  $variables['sort_exposed_form'] = $sort_exposed_form;
}

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

abdelrahman amer’s picture

StatusFileSize
new13.38 KB

Reworked 2894747-114.patch to be compatible with Drupal 10.5.x.

fernly’s picture

StatusFileSize
new12.53 KB

Providing patch based on the current MR, working for Drupal 11.3.3.