Problem/Motivation
------------------
In core/modules/views/js/ajax_view.js, when building the next AJAX request
for a view's pager/exposed-form submit, the code checks whether a URL
parameter is "already part of the exposed form" like this:
this.$exposed_form.find(`input[name="${name}"]`).length === 0
This has two problems:
1. The selector only matches `input` elements, never `select`. Any
select-based exposed filter (e.g. a multi-value select2 widget) is never
recognized as "already in the form".
2. A multi-value field's actual form control is named e.g. "intake[]",
while a previously-pushed URL (built server-side, typically via PHP's
http_build_query(), which defaults to indexed bracket notation) contains
keys like "intake[0]", "intake[1]" - different strings from "intake[]",
so even an exact-name match against `select` would still fail.
As a result, once a select-based multi-value exposed filter is used, stale
or removed values keep reappearing/accumulating in the URL on every
subsequent AJAX submission of that view (intake[0]=..., intake[1]=...,
intake[2]=... piling up), because the exposed form's own current value is
concatenated onto the never-cleaned-up stale one instead of replacing it.
Steps to reproduce
-------------------
1. Create a view with an AJAX-enabled exposed filter on a multi-value field
using a select-based widget (e.g. Better Exposed Filters' select2, or any
multi-value entity reference/taxonomy exposed filter rendered as
2. Submit the exposed form with one value selected.
3. Submit again with a different value selected (or with the previous value
removed).
4. Observe that the resulting URL/request still contains the old value(s)
in addition to the new one, accumulating further with each submission.
Proposed resolution
--------------------
Change the check to also match `select`/`textarea` elements (`:input`
instead of `input`), and strip any bracket suffix from the URL parameter
name before comparing, so indexed URL parameters (name[0], name[1], ...)
are correctly recognized as belonging to the same field as its actual
(unindexed, `name[]`) form control.
| Comment | File | Size | Author |
|---|---|---|---|
| #3 | after-step-c.png | 158.95 KB | girish_lnweb |
| #3 | before-step-c.png | 156.18 KB | girish_lnweb |
| views_ajax_select_exposed_filter_cleanup.patch | 2.07 KB | hulyakucuk |
Comments
Comment #2
hulyakucuk commentedComment #3
girish_lnweb commentedI tested the patch locally and it fixes the problem for me.
Setup: Drupal 11.x (recommended-project, DDEV), PHP 8.3, Olivero. The patch applied cleanly to ajax_view.js. I haven’t tested on main. I used a view of Content with a page display, AJAX on, a mini pager (3 items) and an exposed “Content type” filter with multiple selections allowed. That is a plain core multi-select, so no Better Exposed Filters or select2.
Steps: (a) select Article and Basic page and apply, (b) click the pager’s next link, (c) change the selection to Article only and apply. I compared the views/ajax requests in DevTools with the cache disabled.
Before the patch
(b) type[0]=article&type[1]=page shows up twice in the request.
(c) the request still has type[0]=article&type[1]=page along with type[]=article, so the deselected Basic page value is still sent.
After the patch
(b) type[0]=article&type[1]=page appears once.
(c) only type[]=article is sent.
The results list after (c) shows only Article items.
Comment #4
smustgrave commentedDon't see anything to review here.
Also summary needs to be updated. Not sure if it was copied from AI if so please re-write into own words per the policy https://www.drupal.org/docs/develop/issues/issue-procedures-and-etiquett...