I have an exposed filter with autosubmit and ajax turned on in a view. When I type a few characters in the filter the ajax fires to filter the result and keyboard loses focus, then I have to click on the filter again to continue typing.

The ajax also changes the filter input. when I type "abcdefghijk" in the filter, ajax fires at "c" and by the time I reach "abcdefghijk" my input becomes "abc" all of a sudden and keyboard loses focus.

Comments

makangus’s picture

As suspected, having the exposed filter in a block solves the problem. The problem seems to be the ajax is refreshing the whole page view including the exposed filters when the filters are not in a block.

dawehner’s picture

There is no way around here, from my perspective, either you want to refresh the full view or not, but you have to rerender the exposed filters.

geerlingguy’s picture

Eek. Just hit this interesting behavior (I guess it can't be classified as a 'bug' per-se, re: dereine's post above), and it's quite jarring. I'll try to embed a block above my embedded view with the exposed filters inside, but this seems like major overkill for a UX bug like this.

(This also happens if a user hits the 'return' button while typing. But that's pretty normal behavior, so it's only strange (and happens quite frequently) when a user is slowly typing some characters (e.g. older users), or pauses while typing.

If I have a block view that I'm embedding on a node (using hook_node_view()), is there any way I can put the exposed filters into a separate block? Or do I need to make a page view instead?

[Edit: D'oh! Just realized I'm the OP here. Been spending waaay too much time around d.org lately :(]

geerlingguy’s picture

Just checked into embedding a page view and then placing the block on that page above the page view, and that still refreshes the entire page after a few letters are typed in. For selection menus, this feature works great. However, for text entry fields, like title searches and such, this is quite jarring.

[Edit: Well, I realized I didn't have the 'Use AJAX' toggle on. Setting that to on, then embedding a block for the exposed filters, and placing that block on the appropriate page, all together, works for this feature and allows the textfield to keep the keyboard highlight. It'd still be nice if it could be done in a single block, though - is there any way to separate out the exposed filters from the rest of the view so they don't need to be refreshed?]

makangus’s picture

Being able to separate out the exposed filters from the rest of the view would be nice. I don't really have a problem separating out exposed filters into a block myself and I understand why @dereine said "either you want to refresh the full view or not", but it makes it impossible to do something more complicated (i.e. using Quicktabs to display two Views both with exposed filters) unless I am willing to live with the keyboard focus problem.

FreeFox’s picture

Would it be possible to add some javasript in there that triggers on "lost focus" to set the focus back on the input field? Maybe its a workaround till a good solution in found.

dawehner’s picture

Well sure it would be probably possible to write some custom javascript to get this behaviour back.

dawehner’s picture

Category: bug » task

Let's make this a task.

nod_’s picture

The initial premature submit is a ctools issue as views uses the auto-submit functionnality from ctools #1324238: Not all views exposed forms auto-submit correctly (was: Clean up and improve auto-submit.js0

On a side note, I've been able to use quicktabs to display two views with exposed filters (which get refreshed on submit), just need the views-dev and the patch above for ctools.

the solution of #6 could be implemented in ctools too. I'm guessing that's not a views only problem.

airb’s picture

views-dev + patch not working for me.

nod_’s picture

The patch was only meant to fix the premature submission. and the quicktabs thing is a comment on #5. So what exactly isn't working for you ?

Do you have your exposed filters in a block ? Because you really should, otherwise views replace all HTML from the view including the form and it's very hard if not impossible to keep focus where you want. I'm just rephrasing what has already been told before.

airb’s picture

1. i expected the same problem, that after autosubmit the input field loses focus.
2. i red this issue and your patch.
3. installed views-dev and added your patch -> not worked (view as page lost focus)
4. placed view as block in a panel. -> not worked (lost focus)

(5. i also expected that the date popup is not working in exposed filter+autosubmit with your patch)

ChaseOnTheWeb’s picture

re: #12

4. That's not what is meant. Do the following:
- Your view display must be a Page.
- Under Exposed Form under Advanced, change Expose Form in Block to Yes.
- You then must add the block with the filters to the page you need.

With this configuration, the text box should not lose focus (it is outside of the view, which gets overwritten on every AJAX request).

airb’s picture

i am sorry! i understand how it works... i missed that configuration option. it works now with ctools-dev and views-dev (without the patch) one view page (2 parts) in one panel, exposed form in block view + page view. it was a bit confusing. thanks for your help!

adf1969’s picture

nod_:
What do you mean by "Do you have your exposed filters in a block?"
From what I have read of this issue, by putting the EF in block it will cause the "ajax_command_replace" to only replace the actual "view" results listing, but not the exposed filter.

I see comments in #14 below which seem to indicate a view with a "block" for the filters and a "page" for the results. Is this being done using "panels" or thru the views UI?

I'll take a crack at it while waiting your response. If I figure it out before you respond, I'll post some details.

Thanks for your help.

Andrew.

airb’s picture

hi Andrew!

if you create a view (content pane and page works only, as i see)
you have to set: Advanced / Exposed form / Exposed form in block: Yes
in panels content, you will get an option: panel content / add content / Views / exposed_form_block:"your view"
and you also have to add the page or content pane, as normally, to show the results.

i think this "form in a BLOCK" is an unfortunate naming...

matt__’s picture

Version: 7.x-3.0-rc1 » 7.x-3.0-rc3

So I understand all the posts above, but that still doesn't solve the problem where you need the view as a block (eg. used alongside quicktabs). Is anyone working on optionally separating out the filters from the data for a block view?

MustangGB’s picture

Version: 7.x-3.0-rc3 » 7.x-3.3

Still an issue in latest release.

In fact this is causing a bigger issue for me.
I have view ajax enabled, exposed form autosubmit enabled and an exposed filter for node title.
Typing quickly into the exposed filter works fine (bar the lose of keyboard focus).

However typing slowly will do one of the following, when filtering for the title 'testing':
a) Type 't' then 'e', the autosubmit kicks in after pressing 't' but the 'e' never appears in the inputbox. This is not the end of the world as it could probably be solved by fixing the lose of focus issue.
b) Type 't' then 'e', the autosubmit kicks in after pressing 't' and the 'e' does appear. But instead of an ajax load I am redirected to /view?title=te, this definitely shouldn't be happening.

Both of these are worked around by having the exposed filters as a block. From #11 it would appear the way to fix this is to not replace all view html but only .view-content.

geerlingguy’s picture

Version: 7.x-3.3 » 7.x-3.x-dev

Problem exists in -dev, and any patches submitted should be against that branch.

mxh’s picture

The workaround by using it in a block is very uncomfortable. I have about 20 views where this functionality is needed, but having 20 exposed blocks to separately configure, and many more will be added, is a pain. This just fills up my already overloaded blocks configuration page.

modstore’s picture

I need to display the view as a block, but the workaround only seems to work using the view as a page (or using panels) - I am using display suite though.

Is there a method to allow this to work as essentially 2 blocks, rather than a page with an exposed form block?

Martin Schauer’s picture

This JavaScript-Code embedded in a module of your choice should hopefully offer you a quick-and-dirty-D7-solution for your problem.

	/* =================================================================
	*  Keep focus on auto-submitted text-fields without surrounding block
	*  ============================================================== */

function SetCaretAtEnd(elem) {
  var elemLen = elem.value.length;
  // For IE Only
  if (document.selection) {
      // Set focus
      elem.focus();
      // Use IE Ranges
      var oSel = document.selection.createRange();
      // Reset position to 0 & then set at end
      oSel.moveStart('character', -elemLen);
      oSel.moveStart('character', elemLen);
      oSel.moveEnd('character', 0);
      oSel.select();
  }
  else if (elem.selectionStart || elem.selectionStart == '0') {
      // Firefox/Chrome
      elem.selectionStart = elemLen;
      elem.selectionEnd = elemLen;
      elem.focus();
  } // if
} // SetCaretAtEnd()

var textboxToFocus = {};

jQuery(function($) {
  var addFocusReminder = function(textbox) {
    textbox.bind('keypress keyup', function(e) {
      textboxToFocus.formid = $(this).closest('form').attr('id');
      textboxToFocus.name = $(this).attr('name');
      
      if(e.type == 'keypress') {
        if(e.keyCode != 8) { // everything except return
          textboxToFocus.value = $(this).val() + String.fromCharCode(e.charCode);
        } else {
          textboxToFocus.value = $(this).val().substr(0, $(this).val().length-1)
        }
      }
      else { // keyup
        textboxToFocus.value = $(this).val();
      }
    });
  }

  addFocusReminder($('.view-filters input:text.ctools-auto-submit-processed'));
  $(document).ajaxComplete(function(event,request, settings) {
    if(typeof textboxToFocus.formid !== 'undefined') {
      var textBox = $('#' + textboxToFocus.formid + ' input:text[name="' + textboxToFocus.name + '"]');
      textBox.val(textboxToFocus.value);
      SetCaretAtEnd(textBox[0]);
      addFocusReminder(textBox);
      //textboxToFocus = {}; // if you have other auto-submitted inputs as well
    }
  });
});

The "SetCaretAtEnd"-function was taken from ChrisG at Stack Overflow.

regards,
Martin

dawehner’s picture

Can someone clarify whether this is also a problem in Drupal 8 core? If yes, we have to fill a bug report against core as well.

mallezie’s picture

Issue summary: View changes

I was trying to test this for D8 on simplytest.me, but can't even use exposed filters.
The filters always return no results, and exposing the filter doesn't work.

jaydee1818’s picture

#22 works great for me. Thanks!

bpadaria’s picture

To Martin Schauer,

#22 works like charm!

m4olivei’s picture

Just want to note that if need to have the exposed filter form in a block and using a page isn't an option, then there is this module to consider:

https://drupal.org/project/views_block_filter_block

Thanks,
Matt

jOksanen’s picture

+1 on:

#22 works like charm!

jOksanen’s picture

An additional idea to this issue. I found that changing autosubmit.js to "on change" fixed the issue. This however cannot be patched to be so I added a prevent autosubmit js file to my feature module with the following code. A quick and dirty solution but works.

drupal_add_js(drupal_get_path('module', 'mymodule') . '/js/prevent-auto-submit.js', array('weight' => 10));
(function($){

  Drupal.behaviors.CToolsAutoSubmit = {
    attach: function(context) {
      // 'this' references the form element
      function triggerSubmit (e) {
        var $this = $(this);
        if (!$this.hasClass('ctools-ajaxing')) {
          $this.find('.ctools-auto-submit-click').click();
        }
      }

      // the change event bubbles so we only need to bind it to the outer form
      $('form.ctools-auto-submit-full-form', context)
        .add('.ctools-auto-submit', context)
        .filter('form, select, input:not(:text, :submit)')
        .once('ctools-auto-submit')
        .change(function (e) {
          // don't trigger on text change for full-form
          if ($(e.target).is(':not(:text, :submit, .ctools-auto-submit-exclude)')) {
            triggerSubmit.call(e.target.form);
          }
        });

      // e.keyCode: key
      var discardKeyCode = [
        16, // shift
        17, // ctrl
        18, // alt
        20, // caps lock
        33, // page up
        34, // page down
        35, // end
        36, // home
        37, // left arrow
        38, // up arrow
        39, // right arrow
        40, // down arrow
        9, // tab
        13, // enter
        27  // esc
      ];
      // Don't wait for change event on textfields
      $('.ctools-auto-submit-full-form input:text, input:text.ctools-auto-submit', context)
        .filter(':not(form-item-search-api-views-fulltext input)')
        .once('ctools-auto-submit', function () {
          // each textinput element has his own timeout
          var timeoutID = 0;
          $(this)
            .bind('keydown keyup', function (e) {
              if ($.inArray(e.keyCode, discardKeyCode) === -1) {
                timeoutID && clearTimeout(timeoutID);
              }
            })
            .bind('change', function (e) {
              if ($.inArray(e.keyCode, discardKeyCode) === -1) {
                timeoutID = setTimeout($.proxy(triggerSubmit, this.form), 500);
              }
            });
        });
    }
  }


})(jQuery);
Arjandew’s picture

#22 doesn't work if your view is loaded with a ajax replace command.

You need to add the addFocusReminder in the ajaxComplete:

<?php
        $(document).ajaxComplete(function(event,request, settings) {
              + addFocusReminder($('.view-filters input:text.ctools-auto-submit-processed'));
              
                if(typeof textboxToFocus.formid !== 'undefined') {
                    var textBox = $('#' + textboxToFocus.formid + ' input:text[name="' + textboxToFocus.name + '"]');
                    textBox.val(textboxToFocus.value);
                    SetCaretAtEnd(textBox[0]);
                    addFocusReminder(textBox);
                    //textboxToFocus = {}; // if you have other auto-submitted inputs as well
                }
            });
?>
quotesBro’s picture

#22 works only from the second attempt: when I type in auto-submit textfield and pause for 0.5 second (autosubmit timeout), the view gets reloaded and textfield loses focus. When I click on this field again, type something and pause, the view get reloaded and textfield keeps the focus.
Any idea how to get it to work the first time?

Schnitzer’s picture

In #22

For some unknown reason the line "elem.focus();" in the else if dont work in IE 11.

Shiraz Dindar’s picture

#29 worked for me. thank you!

i did not try #22.

I did try putting my moving my exposed filters into blocks but that didn't work -- the ajax was still working on them.

but #29 seems good.

pasug’s picture

#29 worked great for me.
Focus stays on the same field till i select some auto complete result or trigger enter.

tterranigma’s picture

#29 submits the form when you hit enter and not while typing, and still keeps the focus on the filter.
#22 submits the form after each keypress and keeps the focus on the filter.

I went with #22!

mstrelan’s picture

I think the ideal solution is to emulate the result of having the exposed filters in a block. That is, when the entire view is re-rendered upon ajax completion, the exposed filters are must be outside the html container of the rest of the view.

Simply editing the views-view.tpl.php template and moving the filters breaks the ajax functionality. The form autosubmits, but it reloads the entire page. If this were fixed, there would be other issues introduced, like the Header region would now be below the filters.

Perhaps there could be an option to replace only the view-content and view-empty containers. I have no idea what would be involved to do this.

bernig’s picture

Thanks to #22 and #30 combined, this works with a view embedded inside a ctools modal.

mithaniel’s picture

i would like to try #22 or #30 but i need help.

Where and how can i use thats "JavaScript-Code"?

Sorry, I just started with drupal. If someone can explain me in detail, I would appreciate so much!

Thanks ;)

AaronBauman’s picture

Category: Task » Bug report

Maybe flipping this back to a bug will get it some attention after 6 years.
In 2011 maybe this was cutting edge javascript, but in 2017 keeping focus is the expected behavior.

Anyone know offhand if this is still broken in 8.x / drupal core?

iedesign’s picture

#39 This is still an issue in 8.x when the exposed form is not a block

nithinkolekar’s picture

this also riggers when select list exposed filter with chosen applied which has searching list item functionality.

It can be reproduced by start typing until it filters element and whilst try selecting the list item it already triggered the ajax call with search string.

dbrabon’s picture

This worked for me on a Drupal 7 'Combine fields filter (exposed)' with 'Include reset button', 'Autosubmit', and 'Hide submit button'. I put this code into a JS Injector to run on the search page. You may need to change the "edit-combine" value to match the ID of your search input field. I was having trouble with jQuery only, moving cursor to end of text after focus. So I opted for a javascript solution found here: https://css-tricks.com/snippets/javascript/move-cursor-to-end-of-input/ . The 'focus()' and 'place cursor at end of text' are fired off after each AJAX call using jQuery. I did notice if you type text during the AJAX call that you will loose those key presses.

Javascript Code:

function moveCursorToEnd(el) {
if (typeof el.selectionStart == "number") {
el.selectionStart = el.selectionEnd = el.value.length;
} else if (typeof el.createTextRange != "undefined") {
el.focus();
var range = el.createTextRange();
range.collapse(false);
range.select();
}
}

jQuery( document ).ajaxComplete(function() {
var txtBox=document.getElementById("edit-combine" );
txtBox.focus();
moveCursorToEnd(txtBox);
});

W01F’s picture

Preferably there should be a way for the text entries to continuously dynamically filter the content while typing using AJAX without losing focus on the field at all, but I think a "second-place" option would be to fire the ajax after a 1.5-2 second delay after typing has stopped, while keeping the focus on the text box.

MakaziMtingwa’s picture

#22 worked for me Drupal 8 by replacing

addFocusReminder($('.view-filters input:text.ctools-auto-submit-processed'));

with

addFocusReminder($('.view-filters input:text.form-text'));