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.

Support from Acquia helps fund testing for Drupal Acquia logo

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

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 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.