Problem/Motivation
If there is a View that has exposed filters and then you place multiple of those views on a page, the filters do not work correctly.
What should happen is that each instance of the block can have a different filter setting and display different content.
What happens is that changes made to either filter effect only the content displayed by the second Views block. The Ajax spinner stays on the page. Both filter forms have the same id attribute which is invalid HTML.
Steps to reproduce
Scenario #1
Create a Views block with exposed filters set to use Ajax.
Place this block more than once on the same page using Layout Builder.
Change the filter.
Scenario #2
Create a view with 2 blocks
Make the second one use ajax and have exposed filters
Place on a page
Notice that the ajax on the second page first once and then throws errors about offset.top() being null
Moving second block to above the first fixed it but that shouldn't be the fix
Proposed resolution
Set a new attribute on the view block 'data-drupal-target-view' and use that to determine relationship between view and exposed form block
Remaining tasks
Review
User interface changes
NA
Introduced terminology
NA
API changes
New attribute being added to the view block 'data-drupal-target-view'
Data model changes
NA
Release notes snippet
NA
| Comment | File | Size | Author |
|---|
Issue fork drupal-3163299
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:
- 3163299-views-multiple-ajax-exposed-filters-11.x
changes, plain diff MR !11923
- 3163299-ajax-exposed-filters-9.5.x
changes, plain diff MR !3687 /
changes, plain diff MR !3686
- 3163299-ajax-exposed-filters
changes, plain diff MR !88 /
changes, plain diff MR !3685
- 9.2.x
changes, plain diff MR !4973
- 3163299-views-multiple-ajax-exposed-filters-10.3
changes, plain diff MR !6796
- 3163299-views-multiple-ajax-exposed-filters-not-media-library-10.3
changes, plain diff MR !11201
- 3163299-views-multiple-ajax-exposed-filters
changes, plain diff MR !6791
- 10.3.x
compare
- 11.x
compare
- 10.1.x
compare
Comments
Comment #2
larowlanTo instances of the same form id will always work this way
Comment #3
larowlanComment #4
liam morlandThis is the use case: In Layout Builder, we want to add the same block to the page more than once, but configured differently each time. If we can't do this, we would have to make more than one identical block type with just a different name and be careful to only add each one once.
As it is, when I add more than one instance of a block containing a View with an exposed filter, the filter forms have the same
idattribute. This creates invalid HTML, which Drupal ought to prevent. The forms also don't work as expected.Comment #5
liam morlandThis patch fixes the problem of multiple forms having the same
idattribute.The Views exposed filters still do not work. They are configured to use Ajax, but they still do a page refresh and use the filtering information from the query string in the URL. This is why multiple View blocks use the same filter settings. Ajax filtering needs to work properly for multiple blocks to work.
Comment #7
liam morlandUpdated steps to reproduce.
Comment #8
liam morlandI have discovered that having two different Views blocks with exposed filters will not work correctly. It looks like it only works to have one set of exposed filters per page.
Comment #9
taran2lHere's the patch for the issue. It's not ideal, but afaik there is no way to determine the relation between a view and a exposed form, especially in a complex cases.
Comment #10
taran2lOK, let's try another one
Comment #12
taran2lWell, removing form ID altogether was too radical :)
Comment #14
taran2lAs views exposed form IDs are unique now, loading a form with AJAX adds a random string to the ID. Patch updated
Comment #15
taran2lAdding a test showing the issue
Comment #17
taran2lHm, #15 looks like a random failure, and the test only patch does not work as expected, but for the sake of purity it should be changed to rely on the old markup
Comment #18
taran2lLet's try D9.2 version, as this won't be committed to D8.9.x (I guess)
Comment #19
taran2lComment #20
taran2lAlright, and here is a test-only-patch that does fail "correctly"
Comment #21
taran2lThere is a very similar issue with D7 #1735096: Allow multiple instances of the same exposed filter form on a single page. The proposed patch is almost the same, however, there are updates to the form caching.
Comment #22
taran2lComment #24
taran2lOK, the test-only patch fails as expected
Comment #25
lendudeNice coverage. What we do need to check in the test though that the reload is actually done with AJAX. Calling $assert_session->assertWaitOnAjaxRequest(); doesn't assure that AJAX was used, it could just be that the page reloaded. I'm saying this because some JS changes lead to AJAX stopping to work at all and the exposed form reverting back to just triggering page reloads.
And if at all possible we should get rid of $assert_session->assertWaitOnAjaxRequest(); and replace this with a waitForXYZ method to be more specific in the waits. $assert_session->assertWaitOnAjaxRequest(); leads to random fails unfortunately :(
Comment #26
taran2l@Lendude actually it uses AJAX, and without AJAX it will fail because all forms will have the same value (because there are 3 instances of the same form with the same form elements with the same name) -> all views will have the same filter applied and the test will fail. Works by side effect :)
Anyway, I was not aware of the potential issues caused by using
$assert_session->assertWaitOnAjaxRequest(). Will try to update the test whenever I have spare time.Comment #27
liam morland@Taran2L, is the patch in #18 the same as #15 except ported to 9.2.x? We need to use this on 8.9.x. Thanks
Comment #28
liam morlandI'm trying patch #15 on 8.9. It's working except that the reset buttons redirect me to
<view-matchine-name>/all/all/allinstead of resetting by ajax.Update: I re-installed my site and I am no longer seeing the above problem.
Comment #29
raman.b commentedReplacing usages of
$assert_session->assertWaitOnAjaxRequest();and fixing some minor nits.Comment #30
raman.b commentedShould probably get
$assert_sessionback since it was already thereComment #31
raman.b commentedAlso, just realized that we should have more specific selectors
Comment #33
liam morlandThe patch in #31 is the same as the patch in #18 except for assertWaitOnAjaxRequest() being replaced with waitForElement() and waitForElementRemoved() in tests, and some coding standards fixes. An interdiff is attached.
Comment #34
taran2lLooks good to me, I was deliberately avoiding such precise selectors (so less dependency on the markup), but seems like this is the preferred way
Comment #36
liam morlandI have created an issue branch with the patches from #18 and #31, and made a merge request.
Comment #38
anybodyGreat work here. I just ran into the other case - I have a view consisting of two (or more) blocks (or other view displays), in my example a Map and a results list.
When a user filters the results, all displays of the view should show the same results. On the map and in the result list. I'm not sure if this is or should be in the focus of this issue, but perhaps someone might use this "bug" as expected behavior. Furthermore, it could be helpful to introduce an option to configure that behavior?
Comment #40
marcvangendI fixed core/modules/views/js/ajax_view.es6.js in the issue fork to comply with prettier formatting. That solves the "Custom Commands Failed" test failure.
That said, to move this forward I assume the issue branch should be rebased on upstream 9.4.x, and the MR updated accordingly, but I'm not sure how to do that.
Comment #41
liam morlandIt needs to be manually rebased in a local repository.
Comment #42
marcvangendOK, I rebased against 9.4.x. There was a little bit of conflict resolving involved, but I think I got it all sorted out.
Since the rebase required me to do
git push --force, anyone who has already checked out the issue fork will probably need to do a hard git reset before continuing to work on it.Comment #43
marcvangendI couldn't yet figure out why the test is failing.
It fails in \Drupal\Tests\views\Functional\Plugin\ExposedFormTest::testExposedBlock where it loops over the select options and clicks the apply button for each option. The second iteration of the foreach,
$elements[0]->find('css', 'select')returns NULL instead of the expected NodeElement object.[update]
The part of testExposedBlock mentioned above was added in issue #2681947: Allow 'Put the exposed form in a block' setting to be used with views block displays and committed on the 9.3.x branch in June. So at least that explains why this did not fail before, but only now after rebasing from 9.2.x onto 9.4.x.
Comment #44
marcvangendAll right, I think I found the problem. As said, inside the foreach loop in testExposedBlock, the apply button of the exposed form is clicked. Obviously this triggers a page reload. Before the changes in this issue, the form's
idattribute remained the same, so the next iteration could reuse the xpath reference to the form element. This magically worked, even across page loads, but IMHO this was lazy test design waiting to break. I will push a new commit which finds the current form element inside the foreach.Comment #45
marcvangendComment #46
Belialius commented3163299-31.patch cannot be applied after drupal core update to version 9.3.0
Comment #47
akhildev.cs commentedhi,
check the merge request.(req 88)
patch apply form #45 is working fine for me. (patch applied successfully, view block results are the same on the page. )
patch applied on Drupal 9.4.x-dev.
thankyou.
Comment #48
seanbHere is a patch of the latest MR for 9.3.x.
Comment #49
ranjith_kumar_k_u commentedComment #50
pyrello commentedAs far as I can tell, no one ever addressed the question in #38 by @Anybody. It seems like a potentially valid use case where you want to have one exposed filter block and multiple view block instances that update based on which exposed filters are selected. It seems like the code changes here would disrupt that possibility.
Wondering what this would look like in terms of settings that allow for controlling the behavior. Possibly a view block allow setting to "Choose whether block is unique or connected to other instances." Then a corresponding checkbox in the block form to make the block "Unique" in that it has its own HTML identifier. If it was not unique, then it would fall back to a shared HTML identifier.
Comment #51
seanbJust noticed something interesting going on here. The code originally selects a single form, and then calls
attachExposedFormAjax. With the patch applied,this.$exposed_formcontains multiple forms, andattachExposedFormAjaxis called for each form with the same context.attachExposedFormAjaxusesthis.$exposed_formas a context to find submit buttons, which will cause each form to attach the same AJAX request to all forms (so 3 forms will cause all 3 forms to perform 3 AJAX requests on submit).We should probably use the passed element to find submit buttons in
attachExposedFormAjax. Attached patch seems to fix the issue.Comment #53
seanbNot sure why this fails the new test. Might be an issue with the test somehow relying on Drupal.ajax being attached multiple times to each button?
Comment #54
seanbFound there was a problem using entity browser with the patch #51. Changed the approach a bit and use
once()to make sure the AJAX calls are only attached once to each button.Comment #55
dravenkComment #57
eric_a commentedComment #58
liam morlandRerolled with the "Rebase" button in GitLab. I think anyone can do this if they click on "Get push access" in the ticket first.
Comment #59
ranjith_kumar_k_u commentedComment #63
dpfitzsi commentedIt looks like the patch no longer applies in 9.4.8 (#54 works on 9.4.7).
Comment #64
tim@lammar.be commentedMade a quick change so the patch applies again.
Comment #65
bbu23While the patch in #64 is applying successfully, it doesn't really work as expected. Views with ajax enabled + 2 instances of the exposed form block (Basic style or BEF, tried both) do not do an ajax submit, but it rather refreshes the page which is not the intended behavior.
Comment #66
stefank commentedHi all,
I can confirm #54 works on 9.4.x
Also, tried patches from https://www.drupal.org/project/drupal/issues/2968207, but none of the patches worked, meaning, views with exposed filters using Ajax just refreshed the page rather then submits using Ajax.
Attaching a reroll, as the patch doesnt apply cleanly on 9.4.x
Comment #67
dpfitzsi commentedThe patch in #66 does not apply against 9.4.8.
Comment #68
ameymudras commentedRe-rolling the above patch for Drupal 10x, couldn't generate a interdiff
Comment #70
charly71 commented#54 and #66 do not apply against 9.4.8
PS: #66 has wrong paths with "web" folder..
Comment #71
liam morlandInstead of posting a new patch, it would be better to update the merge request.
Comment #72
mohit_aghera commentedHi @Liam Morland
That makes sense.
I think you are the owner of PR https://git.drupalcode.org/project/drupal/-/merge_requests/88#note_110635
So may be, you'll have to rebase the PR and change the destination branch to 9.5.x, since it will be the active branch.
After doing that, we will have the working PR/patch for the 9.5.x branch as well.
Meanwhile, I have ported the patch for 10.1.x and fixed test case failures.
All 3 failing tests in #68 are passing on local now.
Comment #73
liam morlandI changed the branch to 10.1.x. You should be able to get push access to update it.
Comment #74
cpierce42I was using patch 59, which has stopped working for me in Core 9.4.8. Patch 72 does not apply to Core 9.4.8. I have a use case in 9.4.8 where this applies.
Comment #75
cpierce42Uploading patch that works with Drupal 9.4.8 as I have critical need of it. Someone else might too.
Comment #76
dpfitzsi commentedThank you @cpierce42. I have confirmed that the patch applies on 9.4.8.
Comment #77
cpierce42Re-rolled the patch for 9.4.8 with a condition to exclude the 'widget' type. Fixes condition that would break this patch when media library with 'permissions denied'.
Comment #79
gauravvvv commentedtest only file.
Comment #80
gauravvvv commentedI have fixed the CCF in #77, attached a patch and interdiff for same. Please review
Comment #82
larowlanReroll for 9.5.x
Comment #83
mjpa commentedPatch in #82 doesn't work for us, it removes the ajax_view.js changes present in #80.
#80 applied to 9.5.5 cleanly and works for us.
Comment #90
tgaugesChanging the target branch of the merge request
I created a new merge requests against 9.5.x: https://git.drupalcode.org/project/drupal/-/merge_requests/3687.
Comment #91
charly71 commentedPatch #80 work for us with Drupal 9.5.8 not with 9.5.9
Patch #82 doesn't work at all...
Comment #92
rodrigoaguileraThis issue should be fixed first for Drupal 10 and then backport if it applies.
I left some comments in the MR from #90. I think is the right approach.
Since the project where I need this is in Drupal 9.5.9 you can find attached the patch for convenience. The rebase is quite trivial.
Comment #93
rodrigoaguileraUgh. Now the non-empty patch
Comment #94
taran2lComment #95
taran2lComment #96
taran2lComment #98
taran2lComment #99
taran2lComment #100
taran2lComment #101
taran2lComment #103
taran2lArghhh, I think I have found source of the issue why tests are so unreliable, and its #1852090: Cached render elements can have duplicate HTML IDs .. I think the fix is correct, but the test is not due to issues with duplicate form CSS ids.
Comment #104
taran2lComment #105
smustgrave commentedCan the issue summary be updated to include the proposed solution and any remaining tasks.
Comment #106
smustgrave commentedComment #108
unstatu commentedI have detected that the block preprocess functions are not triggered for the exposed filter blocks when using this patch.
The problem appears because of this file changes
It seems that adding the block render array inside the `content` key avoids to trigger the preprocess functions.
Comment #110
peachez commentedReroll for D10.2
Comment #117
liam morlandThere is no need to make a new merge request. You can force-push the branch of the existing merge request and it will use the new code. It will leave behind a tag pointing at the old code.
Comment #118
pyrello commented@Liam Moreland Good to know. Not sure I would have figured that out on my own and I have yet to discover the docs indicating the proper workflow with MRs yet.
Comment #119
ericdsd commentedTested MR from #116 over core 10.3.5 on views embedded with viewsreference + viewsreference_filter + better_exposed_filter with success.
Thanks a lot !
Comment #120
ericdsd commentedUploading patch from MR 6796 #116 for core 10.3.5
Comment #121
mahmoud barhouma commentedpatch 120 work for me , thank you
Comment #122
bramdriesenI can confirm the latest patch also solved this issue for us.
Comment #123
ericdsd commentedComment #124
smustgrave commentedIssue summary is still incomplete and there are multiple MRs but don’t appear to be one for 11.x
Comment #125
khiminrm commentedThis patch fixes only views in blocks, but not exposed forms in blocks as in https://www.drupal.org/project/drupal/issues/3032353, right?
Trying to find out how to fix conflicts between patches from both issues and apply to project I'm working on now.
Comment #128
ltrainThe 10.3 patch works to fix the issue with multiple views on a page but we have the issue where exposed filters in media library views break when adding blocks with Layout Builder because there is no ajax applied to them. I have created an MR and attached a patch to use the original form IDs for media library views. We're using Gin LB.
Comment #130
strykaizer@laura.j.johnson@gmail.com
I tried reproducing the media browser issue in vanilla core + layout builder, but I could not reproduce this.
It might be a Gin LB specific issue, which I did not test. If so, gin_lb seems to be the appropriate place to fix this issue.
Comment #131
strykaizerWe discussed this issue at dev days with Lendude & Wannesdr.
For ajax updates of exposed forms, which is required for e.g. Facets 3 users, we need ajax enabled exposed forms exposed in a block to update the form(s) too.
However, some users' usecase is that they explicitly use "expose form in block" to prevent the form from updating, which is the current behaviour.
That's why we suggest introducing an extra setting, only visible when "expose form in block" is set to "yes", which allows users to choose how the block form should behave (update or do not update on form submit). For existing views, we keep the old behaviour as default value.
Comment #133
strykaizer3163299-views-multiple-ajax-exposed-filters-11.x is a rework of 3163299-views-multiple-ajax-exposed-filters-10.3 which fixes the test and codestyle.
This patch does not include (optional) replacing of the exposed form for e.g. Facets 3.
I'd suggest to keep this patch focussed on replacing the form ID + using a data attribute as selector for AJAX (instead of an ID)
and fix "optionally replace exposed filters in block form" in a follow up.
Comment #134
mxr576Maybe it worth mentioning that in the latest proposed fix for #3032353: Exposed forms in a block are not updated by AJAX I have introduced a wrapper element around the form that might be also a valid alternative here, although as I wrote in #3032353-63: Exposed forms in a block are not updated by AJAX I do not want to the two issue to become a blocker of each others.
Comment #139
sanderjp commentedPatch from current state of MR !11923
Comment #140
_pratik_I found problem with exposed filter on other views after using #120 and #110 patches.
Re rolled and Adding a quick fix in patch.
Thanks
Comment #141
_pratik_Here is interdiff between patches 110 and 140
thanks
Comment #142
bramdriesen@_pratik_ why update an outdated patch when there is an issue fork with more changes? Why upload a patch when the patch workflow is deprecated?
Update the MR/issue fork if you think your change is relevant.
Comment #143
bramdriesenComment #146
smustgrave commentedHiding patches, closing old MRs
Comment #147
smustgrave commentedRebased as main MR was 600+ commits back, tests are still green
Test coverage is here https://git.drupalcode.org/issue/drupal-3163299/-/jobs/6679875 not posting the output but these failed to match the changes from the MR
Drupal\Tests\views\Functional\Plugin\ExposedFormTest::testExposedBlock with data set "page_display"
Drupal\Tests\views\Functional\Plugin\ExposedFormTest::testExposedBlock with data set "block_display"
Drupal\Tests\views\FunctionalJavascript\BlockExposedFilterAJAXTest::testMultipleExposedFormsForTheSameView
Drupal\Tests\views\Kernel\Plugin\ExposedFormRenderTest::testExposedFormRender
Can vouch that the MR fixes scenario 2.
Don't see any open feedback for this one and believe it's been addressed
Attempted to save credit since last time it was updated.
Comment #148
catchThis needs a rebase unfortunately.
Comment #149
smustgrave commentedWhich came from #343535: Enable bookmarking of AJAX views
I removed it so lets see if it still works.
Comment #150
smustgrave commentedI added back the $exposed_form but still appears to be breaking ajax tests so this will need additional work
Seems some tests are failing as the change here is failing to remove empty parameters like 'title='
Comment #151
smustgrave commentedSo removing getUniqueId() got all the tests back to green. Want to get a review before RTBC.
Comment #152
mjpa commentedsurely the getUniqueId() call is needed as the same view multiple times on the page will end up with duplicate IDs?
Comment #153
smustgrave commentedThat was my thought too so maybe the test case written here wasn’t enough? Because it passes
Comment #154
smustgrave commentedCurious if anyone has used the MR after the last bit of changes?
Comment #155
dcam commentedUnfortunately, I have some bad news. I replicated the issue as described in the issue summary. The MR does work to fix it. But the form IDs are duplicated without
getUniqueId().