9

I have a search field that triggers an autocomplete search while typing. I have it trigger on keyup. This works perfectly in most browsers, but in Firefox on Android, this does not work. It seems like the keyup event is not triggered while typing. This only happens if word suggestions is turned on in the Android keyboard settings.

I see on Google search that the autocomplete search works there for the same setup, so it is obviously possible to do. I wonder how? Is it a special event I need to listen to for this to work?

Additionally I have tried to listen to the events change, keydown and keypress, but none is triggered.

HTML:

<input type="text" id="searchField" 
 autocomplete="off" spellcheck="false" autocorrect="off" />

jQuery event binding:

  $('#searchField').keyup(function (e) {
    var searchValue = $(this).val();
    searchApi._executeAutocomplete(searchValue);
  });

Note:
Sometimes, the key event is triggered, which is typically hitting a key that is not resulting in the process of forming a word. The most obvious here is Enter, which always triggers. Another is Space, which triggers because no word contain a space since space is the definition of a word completed. Backspace triggers if the the last character deleted was not within a word. This means it triggers if you just deleted the last remaining letter of a word (so it is the start of the field, or cursor following a space), but not if you deleted some characters at the end of a word where the cursor is still immediately following a letter. Basically, the key event is not triggered if the key press results in some kind of word suggestion from the keyboard app.

As a side note, I can say that everything works fine in Chrome on the same device.

awe
  • 21,938
  • 6
  • 78
  • 91

3 Answers3

14

You can use the input event instead, that worked for me in Firefox on Android. You could bind event handlers to both input and keyup events for backwards compatibility, but in most modern browsers this will fire both:

$('#searchField').bind('input keyup', function(e){
    var searchValue = $(this).val();
    searchApi._executeAutocomplete(searchValue);
});

Example here: http://jsfiddle.net/JQ928/3/

germankiwi
  • 1,102
  • 10
  • 11
  • After searching for two days for a solution, this finally worked for me. `Keyup` works fine in chrome on android, but to make this work in Firefox as well you have to **add** `input` as well – Christian Strang Sep 17 '13 at 14:35
  • 2
    Just a word of warning here: the fact some browsers will execute your event handler twice is not necessarily a trivial thing, particularly when you fire Ajax requests (like in the example above) as this means redundant network requests. I've just noticed this issue in Google Chrome running on Nexus 5 on Android 4.4.4. – Chris Kobrzak Jul 28 '14 at 12:51
  • Chris, that is a valid point, so if binding to both events you should probably detect if there is already an AJAX call running and ignore the second time it is triggered. For autocomplete I personally think there should be a short delay anyway so you don't make a call for every single keystroke. – germankiwi Jul 28 '14 at 23:18
  • man you just saved me after debugg this for three hours your answer came...great answer – Borza Adrian Jul 31 '14 at 11:10
  • 1
    Does anybody know **why** this happens? I mean the desktop FF behaves as expected, Chrome does in both versions, so it seems that just the mobile FF has this issue... – JepZ Mar 23 '18 at 02:02
0

I found a solution in this answer to another question. The question was a basically "duplicate the text I write dynamically into another part of the page". The answer was including support for catching changes by non-keyboard actions, like pasting text using mouse. It was solved by starting a sniffer on focus in the text field that checks if the value has changed using setInterval(...). It clears the timer on blur.

This solved my problem which was basically that the key events didn't trigger, as well as the "paste by mouse" issue that I didn't realize was a problem until I found this answer...!

This works, but I'm not sure I am totally happy with this solution, because it uses a sniffer. I would be more happy with using some sort of event that is triggered on value change no matter what the cause of the change is. Using the change event would not work, as that is not triggered until focus leaves the field.

Community
  • 1
  • 1
awe
  • 21,938
  • 6
  • 78
  • 91
  • Hey :) it would be great if you could accept the other answer, as your answer seems like a workaround, while the other answer solves the issue. – Christian Strang Sep 17 '13 at 14:37
  • @ChristianStrang: I haven't had the chance to try it out yet. This is a company project where I work, and I haven't been working on this for a while. Have you tried this in a desktop browser using your mouse to paste in a text, which is also a potential issue that my answer solves? – awe Sep 18 '13 at 09:36
  • Code sample for setTimer work around available in http://stackoverflow.com/questions/21388064/onkeypress-onkeydown-onkeyup-events-not-fired-in-firefox-chrome-under-android :) – Cedric Simon Feb 06 '14 at 00:23
0

Trough the fact that Firefox on Android doesn't trigger key-events, but also triggers the input-event some kind of weird, (like if you press one key two events get triggerd, and it also triggers the input-event if you leave the input) I had to write my own event:

(function($){
var $event = $.event,
    $special = $event.special.fennecInput = {
        setup: function(){
            $(this).on('input',$special.handler);
        },
        teardown: function(){
            $(this).off('input',$spceial.handler);
        },
        handler: function(event) {
            var context = this,
                args = arguments,
                dispatch = function() {
                    event.type='fennecInput';
                    $event.dispatch.apply(context,args);
                };
            if($(context).val() != $(context).attr('data-fennecInput-oldval')){
                dispatch();
                $(context).attr('data-fennecInput-oldval',$(context).val());
            }
        }
    };
})(jQuery);

this event gets only triggered if an input-event happens that changes the value, so it doesn't execute events unnecessary.