Problem/Motivation

When an embedded view display (such as a block) has exposed filters, if the view also contains a display with a path (page, export, etc) then the exposed form action will be set to the other display's path. This results in Reset buttons redirecting to other displays for example.

Proposed resolution

This is a tricky one, this could be as involved as rewriting the Drupal\views\Plugin\views\display\DisplayPluginBase::getLinkDisplay logic.

Remaining tasks

Write a failing test
Find a solution

Original report

When a view is setup to use the "Embed" display in a view, using AJAX in the form in any way will cause the action attribute of the HTML form object to be rewritten to submit to '/views/ajax' instead of the current page. This issue is harmless unless the filter in your embedded view uses the Reset button to clear the form and reload the page. When the Reset button is pressed, it'll direct you to /views/ajax instead of your current page.

A variation of this bug is if you have both a Page display setup and an Embed display setup in the view. If both of these displays exist in the same view, then the form's action attribute for the filter in the Embed display will be rewritten to submit to whatever path you setup for the Page display. I'll use this more elaborate scenario in my steps below.

To reproduce this bug:

  1. Create a new view named "Ajax Test"
  2. Change the format to Table. In the settings make the title field sortable
  3. Edit the Title field to give it a label of "Title"
  4. Add the Title field to the Filter Criteria with the filter configured to use the Contains operator. Check the "Expose this filter to visitors" box.
  5. Under Advanced Options, enable AJAX for this view
  6. In the Exposed Form options, make sure Basic is chosen as the type and in the settings check off the box that inserts a Reset button.
  7. Add a "Page" display to this view. Keep all the same settings. Only edit the path for the Page display. Use "/wrong-endpoint" as the path
  8. Save the view

Now we need to embed this view into a page. I'm going to use the Page Example module from the Drupal Examples for Developers set of modules for the dummy page needed to create an embedded view display, but it can be embedded in other ways and would still work the same.

  1. Install and enable the Page Example module to create a sample page we can embed into.
  2. Open 'Drupal\page_example\Controller\PageExampleController'
  3. Edit the description method and append the following before the "return $build" line:

    $build['test'] = views_embed_view('ajax_test', 'embed_1');

Go to the example page at '/examples/page-example'. Your embedded view should be there with the exposed filter. Inspect the HTML form object. The action attribute at this time should be '/examples/page-example'.

Now use the exposed filter to filter the table results. The results will narrow to match your search terms and the "Reset" button will appear. Inspect the form object again. The form will now submit to '/wrong-endpont'. The AJAX parts of the view will continue to work. You can use the table header sort. You can use new search terms and your results will filter as expected, but if you press the Reset button, you'll be redirected to the '/wrong-endpoint' page that was created as a Page type of display for this view.

If you skipped that step of creating the Page type display, and your AJAX Test view only has an Embed display, you will instead get redirected to /views/ajax. Fixed by #2820347: Exposed filter reset redirects user to 404 page on AJAX view when placed as a block so it goes to the current page instead.

This issue does not occur if the view in question is not an embedded view. If you try to repeat this behavior on the Views Page that we created at /wrong-endpoint, you will get the correct behavior. The form's action attribute will not get changed to direct to the wrong page when AJAX rebuilds the form.

CommentFileSizeAuthor
#15 2844823-15.patch1000 bytesbobbygryzynger

Issue fork drupal-2844823

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

hyperlinked created an issue. See original summary.

hyperlinked’s picture

Issue summary: View changes
hyperlinked’s picture

Issue summary: View changes
hyperlinked’s picture

There's an easy workaround for this. Since the embed display will adopt the path specified by a Page display if contained in the same View, you just duplicate your Embed display as a Page and make the path for the page the same as the one the Embed display will be embbed at. This is assuming that the Embed display will always be at a predictable path.

So for example, if your Embed display is going to be embedded on all paths that follow a pattern of "events/[entity_id]", you simply duplicate the embed as a Page display with the path "events/%".

Alternately, don't even create the Embed display. Just create a page display and embed that instead.

lendude’s picture

Project: Views (for Drupal 7) » Drupal core
Version: 8.x-3.x-dev » 8.3.x-dev
Component: exposed filters » views.module
Priority: Major » Normal
Issue tags: -Ajax, -views, -forms, -views filters

Moving to the right queue. Didn't attempt to reproduce.

xjm’s picture

Version: 8.3.x-dev » 8.2.x-dev
hyperlinked’s picture

Well, it appears that the workaround that I mentioned above doesn't work or at least it won't work under most circumstances.

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

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

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

hyperlinked’s picture

I opened this against the 8.2 branch initially and I just tested this against a fresh install of the 8.3 branch. This issue is still active in the lates 8.3-dev release on February 11, 2017.

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.

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.

maacl’s picture

bobbygryzynger’s picture

I'm still seeing this issue in 8.7.x. A somewhat similar issue is mentioned in #8 from #2820347: Exposed filter reset redirects user to 404 page on AJAX view when placed as a block, but was not addressed by the patch there.

bobbygryzynger’s picture

Version: 8.6.x-dev » 8.8.x-dev
Status: Active » Needs review
StatusFileSize
new1000 bytes

Following-up on #8 from #2820347: Exposed filter reset redirects user to 404 page on AJAX view when placed as a block:

In my view I had several blocks with exposed filters that worked until I added page display's. From that moment the exposed filters on the blocks started using the path's of the first page display in the form action, instead of the "current page".

I don't really understand why the code in views gets to decide where to redirect the form action to. "If it doesn't find a display with a path, redirect to current page". It seems so random to me.

The attached patch avoids selecting a routed display for the form action when the display is not a routed display. Let's see what the testbot has to say about it.

Status: Needs review » Needs work

The last submitted patch, 15: 2844823-15.patch, failed testing. View results

bobbygryzynger’s picture

It appears that this logic is relied upon in some areas. Until a stable fix can be achieved, the form's action can be overridden to the correct path if it is known.

For instance:

$form['#action'] = Url::fromRoute('<current>')->toString();
mbovan’s picture

mbovan’s picture

The problem from #15:

  1. was first mentioned in #2820347-8
  2. the current issue summary about a fall back to the first routed display was described in #2820347-87
  3. confirmed later in #2820347-123
  4. and suggested in #2820347-126 that this is not a bug but intended behavior.

To summarize, the current issue title #2844823: Views exposed form action incorrect for embedded views' displays with other displays with paths is a duplicate of #2820347: Exposed filter reset redirects user to 404 page on AJAX view when placed as a block. However, the issue went into another direction (starting from #14).

@bobbygryzynger, would you like to use this issue and argue #2820347-126? If so, could you please update the issue title/summary to match the new goal?

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

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

ludo.r’s picture

This happens as well in D7

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

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now 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.

acbramley’s picture

Title: AJAX filter submission results in form's action attribute being rewritten to '/views/ajax' » Views exposed form action incorrect for embedded views' displays with other displays with paths

This still happens and is easy to reproduce, I just bumped into this issue while using views_data_export which caused the Reset button to trigger the download of the export, quite a confusing bug!

The issue is the same though, the action is set to the export path rather than the current page.

The bug comes all the way from Drupal\views\Plugin\views\display\DisplayPluginBase::getLinkDisplay where it simply chooses the first display that has a path. The flow is:

1) ViewsExposedForm::buildForm calls $view->hasUrl
2) ViewExecutable::hasUrl calls DisplayPluginBase::getRoutedDisplay
3) getRoutedDisplay calls getLinkDisplay which checks the link_display option (this is used by views displays with the "View more" logic and probably other things). However, if this is empty it just finds the first display with a path and returns that

acbramley’s picture

Issue summary: View changes

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.

staceroni’s picture

I tried #15 and it has fixed the form action on a view block with exposed filters + AJAX enabled.

Update: I only noticed comment #17 afterward, so I will override the <form action> in a hook instead.

staceroni’s picture

Using a hook as suggested in #17 does fix the action on the initial page load.
<form action="/current-page">

However, after using a filter (and ajax enabled), the exposed form is updated via javascript and then the action is changed to /views/ajax.
Using the reset button on the form is then broken.
<form action="/views/ajax">

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.

inversed’s picture

For anyone still running into this problem, my workaround was to duplicate the page display that was being unintentionally used to set the path for the embedded Views displays. Then, I disabled the original page display and my embedded displays started setting the form action correctly (with or without AJAX).

seeduardo’s picture

As I think it is related to this issue, I wanted to note that I have posted a potential solution (more of a workaround, really) in a different issue thread: https://www.drupal.org/project/drupal/issues/1109980#comment-14414629

To save you clicking through if not wanted/needed, the gist of my comments are below.

On our project using Drupal Core: 9.3.5, on an Export CSV view attached to a Block view the latter of which is using Better Exposed Filters, the 'Download CSV' button was working fine, but the 'Reset' button also triggered the CSV download. This was the code that "solved" the problem for me:

(function ($, Drupal, drupalSettings) {
  Drupal.behaviors.resetButtonBehavior = {
    attach: function (context, settings) {
      $(context).find('.views-exposed-form input[data-drupal-selector="edit-reset"]').on('click', function(){
        window.location.replace('https://' + window.location.hostname + window.location.pathname);
        return false;
      });
    }
  };
})(jQuery, Drupal, drupalSettings);

The compromise is that the page reloads rather than just resetting the filters, but this is certainly better than the faulty behaviour of the 'Reset' button beforehand. I still feel a better solution needs to be incorporated into Core at some point.

dpi’s picture

#1874838: Allow exposed blocks to use 'Link display' settings seems to be a good solution to this issue in some circumstances.

For example I am rendering a view with a Block display which also has a Views Bulk Export display.

The Block display has filters and Views Bulk Edit on it.

The <form action> attribute will automatically get the Views Bulk Export route on it, because the block is not routable.

If I use the patch from #1874838: Allow exposed blocks to use 'Link display' settings, I'm able to set the path of the real route embedding this page, so it does not pick up the export path. The <form action> attribute will have the value of the custom path.

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.

dubs’s picture

I am embedding a views block in paragraphs, and this code works for me (using hook_form_FORM_ID_alter() ).

if ($form['#id'] == 'views-exposed-form-marketplace-entries-marketplace-entries-block') {
    $input = $form_state->getUserInput();
    $custom_action = $input['custom_action'] ?? Url::fromRoute('<current>')->toString();
    $form['custom_action'] = [
      '#type' => 'hidden',
      '#value' => $custom_action,
    ];
    $form['#action'] = $custom_action;
  }
alison’s picture

I found this issue right after submitting a new one, darn.
#3346820: On views with AJAX enabled, exposed filter "reset" causes (non-ajax) page load

I'm not closing my new one quite yet, though, for a few reasons (in no particular order):

  1. I think the fact that the reset button causes a page load when AJAX is enabled is the root cause of the issue -- I think even on a view page display, hitting Reset shouldn't cause a page load, right?
  2. When I reproduce the issue, the form action is the view page display URL from the start, not just after I submit filters.
  3. I think my steps to reproduce are simpler? (but if folks agree and if the issue I created is closed as a duplicate, I could easily copy those steps to reproduce into here).

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.

liam morland’s picture

As noted in #23, the problem seems to be that ::getLinkDisplay() chooses the first display that has a path. Why would it ever make sense to do this? This will often give the path of a different display and I don't see how that would ever be correct.

This was fixed in views_block_filter_block by removing the loop that searches other displays; see #2979690: Incorrect form action URL for views that have page displays.

I was able to fix it for our purposes with this:

/**
 * Implements hook_form_FORM_ID_alter().
 */
function hook_form_views_exposed_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  // Fix Views exposed filter form action.
  // @see https://www.drupal.org/project/drupal/issues/2844823
  $form['#action'] = \Drupal::request()->getPathInfo();
}
marksmith’s picture

This is still an issue in Drupal 11.1 and it can become quite annoying for blocks with exposed filters (I use page reload, arguments, query parameters, and contextual filters in my block, no AJAX).

When the first views display item with path (page, rss, etc.) in the current view is a view with a dynamic route (like node/%node/somepage), this also leads to a routing error, like this one: Symfony\Component\Routing\Exception\MissingMandatoryParametersException: Some mandatory parameters are missing ("node") to generate a URL for route "view.viewname.page_1". in Drupal\Core\Routing\UrlGenerator->doGenerate() (line 180 of /var/www/html/mysite/web/core/lib/Drupal/Core/Routing/UrlGenerator.php).

The root cause of the issue was described by #23 (for Drupal 9) and reinforced in #38, and a workaround was suggested in #30.

One small addition though that might help others. By default it's the first path within the current view which is chosen by the block. However, in the Pager > Link display section you can choose other displays with a path from the current (!) view as well. Only the "None" and "Custom URL" options of the Link display are not respected. (And ultimately the default None option is not respected by getLinkDisplay). So I created a random page (with the /node path), disabled it, and use this as a reference link for the block with the exposed filters.

acbramley’s picture

This is probably a duplicate of #2840283: Views exposed form action incorrect when view also has a page display - there's a WIP MR up over there but as per comment 75 BC is going to be tricky for this fix.

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

acbramley’s picture

Status: Needs work » Postponed (maintainer needs more info)

Marking PMNMI based on #41 if anyone disagrees that this is a duplicate, feel free to reopen this and explain why. Otherwise we can close this out after 3 months.

smustgrave’s picture

Wanted to bump 1 more time before closing, since it had a lot of activity at one point.

anybody’s picture

Thanks @smustgrave! I added a link to this one in #2840283: Views exposed form action incorrect when view also has a page display so we don't lose this entirely!

joelpittet’s picture

Status: Postponed (maintainer needs more info) » Needs review

@acbramley RE #41 I don’t think this is a duplicate of #2840283: Views exposed form action incorrect when view also has a page display, though that issue may provide a workaround in some cases.

That issue is about explicitly selecting a display. This issue is addressing a different problem. When the current display does not have a route, Views ends up guessing which routed display to use for the exposed form action.

That guess can be wrong. If the view has multiple routed displays, Views may pick a different one entirely, such as data_export, ical_feed, or any other display with a route. This leads to incorrect behaviour. In practice, it often appears to be assuming a page display 🤞

The patch here is trying to fix that underlying guessing logic so the behaviour is predictable, rather than relying on display ordering or duplication as a workaround.

Marking this back to Needs Review. I will move this to an MR shortly and try to add a test.

If the current behaviour is considered intentional, an update path that allows an unrouted display to explicitly reference a routed one may be a safer alternative.

smustgrave’s picture

Status: Needs review » Needs work

Appears to have two MRs, both having some issues, can one be closed please

joelpittet changed the visibility of the branch 2844823-views-exposed-form to hidden.

joelpittet’s picture

Status: Needs work » Needs review

Sure, closed the one that was just #15 because I detoured a bit. I guess I forgot to submit my comment for why on the other computer...

acbramley’s picture

Status: Needs review » Postponed (maintainer needs more info)

Re #46

That issue is about explicitly selecting a display.

I'm not sure what you're referring to?

That issue is about explicitly selecting a display. This issue is addressing a different problem. When the current display does not have a route, Views ends up guessing which routed display to use for the exposed form action.

That is exactly what #2840283: Views exposed form action incorrect when view also has a page display is about too. Views guesses the first display that has a route and uses that for the form action.

joelpittet’s picture

Status: Postponed (maintainer needs more info) » Closed (duplicate)

@acbramley RE #52

I re-read both issues and compared the current MRs. I think you’re right that they’re effectively the same problem now: avoiding “guessed” routed displays for unrouted displays, while still honouring an explicitly configured link_display and falling back to the current page (especially for AJAX rebuilds). The newest MR 13479 are clearly converging, so treating this as a duplicate seems reasonable.

For context on my earlier hesitation: some of the earlier patches and especially MR 8053 read to me as focused on making an explicit Link display configuration work, rather than removing the implicit “guessing” entirely. That’s what initially made these feel distinct.

After revisiting the summaries and the more recent MRs, it’s clear they’re addressing the same underlying issue. I’ll close this issue, hide the patches and MR 8053, and move any relevant tests or fixes over to the other issue.

Still a bit unsure if I should iterate on MR 13479, or create a new one. I will start with a fork so I don't step on toes... too much. 👣

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.