Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed: Views exposed filter with autosubmit and AJAX loses keyboard focus. #3166

Closed
klonos opened this issue Jun 6, 2018 · 28 comments · Fixed by backdrop/backdrop#4653
Closed

Comments

@klonos
Copy link
Member

klonos commented Jun 6, 2018

Describe your issue or idea

Views 7.x known issue: https://www.drupal.org/project/views/issues/1217948

https://drupal.stackexchange.com/questions/29503/views-exposed-filter-auto-submit-loses-focus

Steps to reproduce

  1. On a vanilla Backdrop installation, install the Devel module, and enable it + the Devel Generate submodule.
  2. Use Devel Generate, to generate a large(ish) amount of content (say 100 or 500 nodes).
  3. Edit the "Administer content" view:
    • Enable AJAX from the "Other" section of options.
    • In the "Exposed form" section, click the "Settings" link of the "Exposed form style" option, scroll to the bottom of the dialog, and enable the "Autosubmit" option.
  4. Save the view.
  5. Head to admin/content, and start typing in the "Title contains" exposed filter...

Actual behavior

When the form autosubmits (after you have typed a couple of characters in the exposed text field), the text box loses focus. The user now needs to click on the text filter again, then as they start typing and autosubmit kicks in, the filter loses focus again. Repeat...

Typing quickly into the exposed filter works fine, however typing slowly will cause focus loss.

Some people report that separating the exposed form into a block fixes the problem, however this is not an option if the view itself is a block display.

Expected behavior

The exposed text filters do not lose focus as the user types and the results listing gets refreshed.

@antijingoist
Copy link

The drupal issue points out that the entire view is being refreshed, which results in focus being lost, and the reason it can't be set after the results are loaded (the fields no longer exist). Apparently moving the exposed form into a block resolves this because now the form is not being refreshed with the view.

All things considered, it at least doesn't seem like working around this in autosubmit.js is a bad idea, and may be better than letting this exist as is for another decade.

This is what worked for me in core/misc/autosubmit.js :

    function triggerSubmit (e) {
      var $this = $(this);
      // Save the field's ID to refer to it later. Get the current cursor position
      var searchFieldID = '#' + $this.find('.autosubmit-processed').attr('id');
      var searchFieldCursor = $(searchFieldID)[0].selectionStart;
      
      $this.find('.autosubmit-click').click();

      //Wait some time for the view to refresh, and then find the new field by it's id and place the cursor back where it was
      setTimeout(function() {
              $(searchFieldID).focus();
              $(searchFieldID)[0].setSelectionRange(searchFieldCursor,searchFieldCursor);
          }, 100);

    }

The wait time is admittedly arbitrary, and the setTimeout could more stable by hooking into the view refreshing, but it's also a 10 year old bug that doesn't seem to have gotten traction.

@klonos
Copy link
Member Author

klonos commented Jul 27, 2020

Thanks @antijingoist for taking the time to share the solution that worked for you. I've put it into a PR here: backdrop/backdrop#3200

I've tested in a vanilla Backdrop installation, and then tested in the PR sandbox, however the problem is still there with the fix 😓

(I have added the steps to reproduce this in the issue summary above).

Having said that, I am uneasy about adding arbitrary timeouts. I would love it if a JS guru out there came up with a solution that used some kind of polling instead. I did some research about that, and people seem to suggest Promise API for such cases - but my JS skills are laughable, so I wouldn't know 🤷

Some articles that seemed related/helpful to me:

https://levelup.gitconnected.com/polling-in-javascript-ab2d6378705a
https://davidwalsh.name/javascript-polling
https://javascript.info/long-polling
https://github.blog/2009-07-30-smart-js-polling
https://www.thegreatcodeadventure.com/polling-with-javascript-jquery

@antijingoist
Copy link

Is the sandbox the one at the 3200 link? It looked like the original autosubmit.js is in the cache.
If I create a local override with a test view it seems to work.

That said, i was hoping views had an event I could listen for but I guess it doesn't?

@klonos
Copy link
Member Author

klonos commented Jul 28, 2020

@antijingoist yes, that's the automatically generated sandbox. When I tested earlier, I made sure that I had caches cleared. I have now checked again, and I have this time disabled js aggregation. I then inspected the page source and js assets loaded, and have confirmed that the proper autosubmit.js with the changes is loaded:

image

Still doesn't work 🤷

I'll let others test and confirm this.

@antijingoist
Copy link

antijingoist commented Oct 9, 2020

Intended to respond sooner.... :D

Its a poor solution, because at least w/ my setup it works consistently but on mobile it's a flickering keyboard mess. To continue down this path is a can of worms. I have to blanket disable searching on smaller screens just to not spend too much time on it. :-/

edit: I had to up the timeout to 250 for consistency.

@yorkshire-pudding
Copy link
Member

Hi @klonos and @antijingoist - I couldn't apply the diff from backdrop/backdrop/pull/3200 so created a new PR as I know you may take a little while to get round to rebasing.
With the suggestion above to use 250, this works well on desktop, but not so well on mobile. Like @antijingoist said, I may need to disable text search for mobile.

It would be great to get some JS experts on this as it does seem a major UX fail at the moment.

@indigoxela
Copy link
Member

@yorkshire-pudding no expert, so started with testing...

However, in Firefox at least, this seems to be quite unreliable. Sometimes the focus's back, sometimes (mostly) not.
Raising the timeout (wait time) to 1000 seems to work for me, but a huge timeout doesn't seem to make much sense to me, either (and gives a visual glitch).

That's a general problem with setTimeout workarounds, I guess.

@indigoxela
Copy link
Member

indigoxela commented Feb 1, 2024

To further complicate things here, I came up with a new idea: add an event listener on "ajaxStop" (fired by jQuery ajax), and grab the info from a data attribute parked on body.

Still weird, but that way we're not fiddling with timeout guessing, which can be hard, if not impossible.
I have to admit, I don't fully understand all code in autosubmit.js, don't even know, when parts of it even run.

@yorkshire-pudding or @klonos this approach is only provided as PR to play with. I don't think, it's the ideal solution. But IMO autosubmit in general is a sinister pattern. 😉

@yorkshire-pudding
Copy link
Member

Hi @indigoxela - I've given this a test in both desktop with hundreds of items (can't check on genuine mobile locally and don't have a test remote site at the moment) and in the sandbox with smaller numbers on the mobile.

Both seem to work well and behave as we want them to behave. Even if typing slowly, the text box retains focus.

I'm all in favour of this approach but is there any particular reason why this is not ideal?

@indigoxela
Copy link
Member

I'm all in favour of this approach but is there any particular reason why this is not ideal?

The advantage of an event driven approach is that things like a slow database, complex view build, or network latency... wouldn't matter. jQuery emits the event, as soon as ajax is done.

The timeout approach has no way to react on slow/fast view rebuild - it's "one size fits all" (and fails on slow pages).

However, I didn't mean to derail this issue in any way, just wanted to provide an alternative idea. 😉

@yorkshire-pudding
Copy link
Member

@indigoxela

However, I didn't mean to derail this issue in any way, just wanted to provide an alternative idea. 

I think you might misunderstand me. I think the alternative approach you have provided is ideal. I was querying your suggestion that your pr wasn't ideal when I think it is. I couldn't find any fault with your approach

@indigoxela
Copy link
Member

I think you might misunderstand me

Yes, I completely got it wrong. 🙈 (reopened PR now)

It's not ideal, as it might interfere with other stuff and eventually runs even if it doesn't need to.

And it's a bit unusual, but I couldn't avoid to "grab outside" to park info somewhere outside the view - as that gets replaced completely, including the triggering form itself, as long as we're not using the exposed-form-as-block setting.

@antijingoist
Copy link

It's not ideal, as it might interfere with other stuff and eventually runs even if it doesn't need to.

This bug has been around for how long? I think any progress is an ideal solution. Yours way better than mine too. 🤣

@indigoxela
Copy link
Member

I updated the focus code to not run, if it's an independent block, anyway. And made the comments a bit more verbose. Let me know, it that's too verbose now. 😉

Anyway, I think, it's ready for more testing and review... the third PR here - maybe it's time to close some. 😉

@indigoxela indigoxela removed their assignment Feb 9, 2024
@yorkshire-pudding
Copy link
Member

Thank you so much for giving it a go @indigoxela .

@argiepiano
Copy link

argiepiano commented Feb 9, 2024

@yorkshire-pudding, @klonos : while the PR does present the problem you describe, please notice that autocomplete fields like Name do not work with the views filter autosubmit code available in Backdrop now - even without this PR. Those autocomplete fields will "barf" even with the current version of Backdrop if the Views filter has an autosubmit. So this is a separate bug. You should not use an autocomplete field like username to test this PR.

However, I do see the problem you point out: if you have (say) two text fields as filters, the focus will go to the first field that was ever autosubmitted.

I have played a bit with this and I believe I have found a solution based on @indigoxela's. I'll submit a PR shortly.

@argiepiano
Copy link

I've provided an alternative PR largely based on @indigoxela's (thank you!!).

To test, do not use an autocomplete field in the filters! Read above. Please test with two text fields (you'll need to add a text field to your content types).

Also test the select boxes - when using one of those, the focus is taken away from the last text field used.

@yorkshire-pudding
Copy link
Member

yorkshire-pudding commented Feb 9, 2024

Thanks @argiepiano . I've given this a quick test in the tugboat

chrome_1N7fHYLfgD

I added a filter for body field using the contains operator and it works well.

EDIT: Also tested on Android mobile and works well.

@indigoxela
Copy link
Member

indigoxela commented Feb 10, 2024

@argiepiano many thanks for coming to the rescue here. 🙏

An additional function param seems the proper solution. 👍 RTBC

@quicksketch
Copy link
Member

Hi @argiepiano, I reviewed and tested your code. The fix works but I think it might cause some conflicts if autosubmit.js gets used outside of views, or if another JS file attempts to bind to the ajaxStop event. I left a comment on the PR: backdrop/backdrop#4653 (review)

And I filed a PR against yours with the changes I think might avoid conflicts: argiepiano/backdrop#2

@argiepiano
Copy link

Thanks, @quicksketch - looks great. I've merged your PR and resubmitted.

@quicksketch
Copy link
Member

Thanks @argiepiano! I merged backdrop/backdrop#4653 into 1.x and 1.27.x. Thanks to @klonos, @antijingoist, @yorkshire-pudding, and @indigoxela for collaborating on the solution for this issue!

@jenlampton jenlampton changed the title [UX] Views: exposed filter with autosubmit and AJAX loses keyboard focus Fixed: Views exposed filter with autosubmit and AJAX loses keyboard focus. Mar 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment