- Issue created by @xopoc
- 🇮🇳India DimpleL
Hi, As a workaround, you can use the setting available under Advanced called "Use AJAX." Setting "Use AJAX" to "yes" will resolve the issue for now.
- Status changed to Closed: works as designed
12 months ago 3:12pm 7 August 2024 - 🇳🇱Netherlands Lendude Amsterdam
This is by design, Views will look for the first display with a path and use that. You can try #2 or make the block and page be separate Views and not 2 displays on the same View.
- 🇺🇸United States RichardDavies Portland, Oregon
I'm sorry, but if this is "works as designed" then I think this is poorly designed. Please explain to me why I'd want the exposed filters in my view block to target another random display in that view. You said it uses the "first" display with a path, but it doesn't use the first display according to the configured display order within the view, it uses the first display defined in the view's YAML config file.
If this works as expected with a view containing only a single block, then it should work the same with a block in a view that also contains other displays.
- 🇺🇸United States RichardDavies Portland, Oregon
There's a similar problem if you enable Views Bulk Operations on a view embedded as a block. The bulk operations also incorrectly target the wrong page path. However, in this case, enabling AJAX doesn't work as a workaround. So you're telling me that now I need to recreate this block in a completely new separate view and reconfigure my pages/blocks just because I've added bulk operations and this is by design?
- 🇺🇸United States RichardDavies Portland, Oregon
Reopening because you shouldn't need to completely reconfigure your views just because you add bulk operations to a certain display.
- Status changed to Active
6 months ago 12:36pm 29 January 2025 - 🇳🇿New Zealand quietone
Changes are made on on 11.x (our main development branch) first, and are then back ported as needed according to the Core change policies → .
- 🇦🇺Australia NicolasH
I went through exactly the same issue, including VBO and ajax not resolving this. Only thing to add that I started with an embed display, same thing, then switched to block.
Also agree with richarddavies that "by design" is a bit of a stretch. I have not come across other situations where different displays inherit properties without there being a way to overwrite it per display. I get that there is no page path on a block or embed where I could possibly overwrite it, but in that case it should be implied, not borrowing from another display without any indication that it's doing so.
IF a redirect path is required in scenarios like exposed filters and VBO, maybe this could be a setting with replacement patterns? And even if ajax is solving the exposed filters case, most users will see ajax as an option, not a requirement I'd say.
- 🇮🇳India Ishani Patel
Hello,
I've checked the problem and I have an approach for that,
1) we can enable AJAX for the View
- In the Advanced section, locate the Use AJAX setting and set it to Yes.
2) Configure the Exposed Form as a Block
- Go to the advanced section and set the Exposed form in block to Yes.
3) Modify the Form's Action Attribute
- We can Implement hook_form_alter() in the custom module to change the form's action URL and set the form's action to the current
page's URL.Thank you!
- 🇺🇸United States themic8 USA
I'm encountering a similar issue. The view functions correctly when AJAX is enabled, but when submitting an exposed filter with AJAX disabled, the form redirects to an incorrect path.
The affected view is a page display that uses a contextual argument, and the exposed filters are placed in a block using the Better Exposed Filters (BEF) module, using datasources from a Search API index.
By modifying the form's action attribute using hook_form_alter(), I was able to redirect to the correct path (Thank you Ishani). However, I see this as more of a temporary workaround, it can become quite cumbersome if it needs to be applied across multiple views.
Drupal Core: 10.4.5
BEF: 7.0.5 - 🇺🇸United States ccloyd
This "design" functionality is bad design, especially if you are updating from an earlier version of Drupal. This breaks legacy views that have multiple displays with exposed filters in a single view. As noted above, simply setting AJAX to "Yes" isn't always a fix. We have to rebuild almost every view on every Drupal site we run and grow our number of views exponentially, or write tons of hook_form_alter case statements to target all the different exposed forms so they redirect properly, because of this new design decision.
- 🇺🇸United States zooney
What's happening is that the exposed form in the view is having its action attribute set to the first available path in the view if it exists. I'm not certain as to why this design decision was made, unless it's a common use case to have a views block display redirect to a full page view or something similar to that. It all hinges more or less on the internal setting of the view called "link_display".
I took the time to follow through the Drupal (version 10.4.5) code to see how this is currently working.
In web/core/modules/views/src/Form/ViewsExposedForm.php in the buildForm() method starting on line 125:
if (!$view->hasUrl()) { // On any non views.ajax route, use the current route for the form action. if ($this->getRouteMatch()->getRouteName() !== 'views.ajax') { $form_action = Url::fromRoute('<current>')->toString(); } else { // On the views.ajax route, set the action to the page we were on. $form_action = Url::fromUserInput($this->currentPathStack->getPath())->toString(); } } else { $form_action = $view->getUrl()->toString(); } $form['#action'] = $form_action;
If it's a view with, for example, just a block display, the form action would just be set to the current path.
Otherwise, if it's, for example, a block display with a page display, it's going to be pulling the form action from $view->getUrl() defined in web/core/modules/views/src/ViewExecutable.php starting on line 2018:
public function getUrl($args = NULL, $display_id = NULL) { if (!empty($this->override_url)) { return $this->override_url; } $display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay(); ...etc.
...which get the $display_handler from the current display in getRoutedDisplay() in web/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php (starting on line 750):
public function getRoutedDisplay() { // If this display has a route, return this display. if ($this instanceof DisplayRouterInterface) { return $this; } // If the display does not have a route (e.g. a block display), get the // route for the linked display. $display_id = $this->getLinkDisplay(); if ($display_id && $this->view->displayHandlers->has($display_id) && is_object($this->view->displayHandlers->get($display_id))) { return $this->view->displayHandlers->get($display_id)->getRoutedDisplay(); } // No routed display exists, so return NULL return NULL; }
...which will call getLinkDisplay() starting on line 717 of the same file (web/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php) :
public function getLinkDisplay() { $display_id = $this->getOption('link_display'); // If unknown, pick the first one. if (empty($display_id) || !$this->view->displayHandlers->has($display_id)) { foreach ($this->view->displayHandlers as $display_id => $display) { if (!empty($display) && $display->hasPath()) { return $display_id; } } } else { return $display_id; } // Fall-through returns NULL. }
...which essentially will eventually pull the path of the first display which has a path (if I'm reading the code correctly).
I'm not entirely sure if a patch is possible here, but if at some point in the code, if the right conditions are tested, or if some new setting were added to Views (e.g. something like "Don't redirect exposed form"), I guess something could be put together along those lines.
Ultimately, whether or not "works as designed" is valid would seem to depend on what the user requirements actually are, I guess...
The alternatives and workarounds have probably all been covered (making a separate view, using hooks, or using AJAX), but this will hopefully provide some insight as to what's happening.