Programmatically triggering typeahead.js result display
Asked Answered
A

17

38

I am using Twitter's typeahead.js (https://github.com/twitter/typeahead.js/) on an input field which is pre filled from a query string. After loading the page, i'd like to programmatically trigger the display of typeahead results without the user needing to type anything in the form field.

Out of the box, typeahead.js is only triggered if the user manually types something into the input field and i can not find any method in typeahead.js which i could call to trigger the display of results.

Any pointers would be greatly appreciated.

Thanks!

Athanasius answered 27/2, 2013 at 14:50 Comment(2)
Thanks for all the fantastic answers folks! I picked the one via triggering input since that also forces typeahead to search for the keyword before displaying the results (a requirement for me, which i realize was not in my question). Thanks again. Stackoverflow is way better than sliced bread.Aftonag
can use prefetch featureMasera
H
51

Triggering input seems to do it.

$(".typeahead").eq(0).val("Uni").trigger("input");

Tested this on the example page.

Hung answered 27/2, 2013 at 15:18 Comment(15)
Hi, this works beautifully except in IE (who would have guessed). IE just seems to return a jQuery object as shown here: shorttext.com/SuWiMi I am not good enough in JS to debug this, so if anyone would have a suggestion, i'd love to hear it. Thanks!Aftonag
swap it to "paste" instead of "input"Hung
Wow, so easy. Thanks a lot! How would you find that out? Is IE simply not supporting the change event but the paste event?Aftonag
And without the "Uni", can you do it? =\Mcclees
What are you talking about @AlixAxel?Hung
@epascarello: Triggering typeahead.js to open and show every prefetched item, and not just those that have Uni tokens.Mcclees
For anyone looking at this for later versions of typeahead you can use $(".typeahead").typeahead("setQuery","Uni").focus(); because setQuery is the preferred API approach to setting a query value.Dioxide
How can you have it display all the prefetched items? Trying to make it behave sort of like a select box, so the user clicks in the text input and they see a list of all the prefetched items.Spectacle
@Pricey: I think setQuery was removed in 0.10. I tried it and I get an errorUralian
@Spectacle You don't, typeahead is not intended for that.. try using select2Dioxide
@Uralian I can't see it in their documents any more (0.10+) but it's still in the code so I'm only presuming it should still be supported in some way... I was using it in (0.9), my guess is you now do $('.typeahead').typeahead('val', myVal);Dioxide
@Pricey: I also see it in their code, albeit wrapped in a private variable (_select). I am trying $('.typeahead').typeahead('val', myVal) and that too is not working either for me (in 0.10+). The error is: TypeError: i[n] is not a function. I am still digging on this trying to figure it out. Programmatically trigging events like "typeahead:selected" works though.Uralian
@Uralian what version of jQuery are you using? Typeahead needs 1.9+ and that error looks like a minified one so maybe you can try running it with a debug version of typeahead to see where the error occursDioxide
@Pricey: Good question. I am using jQuery 1.8.2 (I have to). I know Typeahead supports 1.9+. That is worth investigating.Uralian
@Pricey: Forget what I said. The mistake was that I was using twitter bootstrap typeahead instead of twitter typeahead. When I went twitter typeahead, what you said work fine.Uralian
A
16

According to my tests (see fiddle), the focus() method is necessary in order to display the dropdown. So:

theVal = $('.typeahead').val();
$(".typeahead").typeahead('val', '')
$(".typeahead").focus().typeahead('val',theVal).focus();
  • On line 1, we're assigning the current value of the Typeahead input to the variable theVal;
  • On line 2 we simply reset typeahead's computed value; and
  • On line 3 we're putting back the original value and the focus, which results in the suggestion dropdown displaying as if the user had typed something.

I actually needed this to strongly encourage users to select from the Bloodhound suggestions coming from a geocoding API call so I could ensure the coordinates were obtained by the client prior to submitting a form.

Ailina answered 13/5, 2014 at 17:46 Comment(0)
D
10
$(".typeahead").typeahead('lookup').focus();

triggers with existing value of input. you can change the value in advance of course

Duffer answered 5/11, 2013 at 14:35 Comment(0)
Y
9

To anyone finding this issue with twitter's typeahead after version 0.11.1, here is how I solved it with one line:

$(".typeahead-input").typeahead('val', "cookie")
                     .trigger("input")
                     .typeahead('open');
Ynez answered 17/7, 2015 at 16:4 Comment(0)
J
8

As of Typeahead v0.10.1, changing the value of the typeahead will trigger another query and open the dropdown:

var val = $(".typeahead").typeahead('val');
$(".typeahead").typeahead('val', '');
$(".typeahead").typeahead('val', val);
Jodoin answered 3/3, 2014 at 8:39 Comment(1)
this is the only one that worked for me (v0.11.1), except that I had to change the first line to: var val = $("#original-input-id").typeahead('val'); where #original-input-id is the id of my input textfield on which I've added the .typeahead classColoratura
L
5

I used twitter bootstrap typeahead, and wamted that on focus, the suggestion list will open. The answers here didn't quite work for me, so I wrote this simple directive (requires jquery):

.directive('typeaheadFocusTrigger', function() {
        return {
            limit: 'A',
            link: function(scope, element, attrs) {
                $(element).on('focus', function(e) {
                    var $target = $(e.target);
                    var origVal = $target.eq(0).val();
                    $target.eq(0).val('').trigger('input')
                    .eq(0).val(origVal).trigger('input');
                });
            }
        }
    });

Now just add this attribute, and it will trigger on focus

<input typeahead-focus-trigger typeahead="">
Libre answered 19/11, 2014 at 9:52 Comment(1)
trigger('input') doesn't on IE So just updated it to: trigger('change') for all browses.Hiram
M
5

Using: Typeahead v0.10.5

Don't use: $('.typeahead').typeahead('open');

This currently does not work. Source: https://github.com/twitter/typeahead.js/issues/798. As a temporary fix, use a a custom jQuery keydown event (after you have instantiated the typeahead):

var ttInstance = $('.typeahead').typeahead( config ); // Create Typeahead
ttInstance.typeahead('val', 'pancakes'); // Set an initial value

var evt = jQuery.Event('keydown');
evt.keyCode = evt.which = 40;
ttInstance.trigger(evt); // Opens the dropdown
Myrlmyrle answered 11/3, 2015 at 20:31 Comment(1)
Out of all answers given here, this was the only one that worked for me.Delegacy
L
3

Looking through the source code, it appears to store a TypeaheadView object in the element data under the key typeahead. This TypeaheadView object has an internal method, _showDropdown, which is internally bound to the focus event (and a few others).

I would not recommend doing this, but you should be able to call that internal method manually:

$('#yourTypeaheadElement').data('typeahead')._showDropdown();

Alternatively, have you just tried simply focusing your typeahead element when the page loads (after initializing it as a typeahead element, of course):

// after page loads and yourTypeaheadElement is initialized as a typeahead
$('#yourTypeaheadElement').focus();
Lynellelynett answered 27/2, 2013 at 15:6 Comment(1)
This doesn't seem to be for typeahead*.js*.Mcclees
C
3

None of these will work unless you deliberately put 'typeahead' into the classes of your input tag. If you don't feel the need to do this (it's not necessary for it to work), you're better off using the class written onto the input tag by typeahead.js. It's ".tt-input". Here's the example I cribbed from Sam_Butler, recoded for the new CSS class. This works for me in the most recent typeahead 0.10.5:

var theVal = jQuery('.tt-input').val();
jQuery(".tt-input").typeahead('val', 're')
jQuery(".tt-input").focus().typeahead('val',theVal).focus();
Chromatic answered 1/4, 2015 at 15:44 Comment(0)
W
2

I took a look at the source code and found this undocumented way:

var $myinput = $('#myinput');
$myinput.data('typeahead')._showDropdown()
Worktable answered 27/2, 2013 at 15:5 Comment(0)
B
2

This should work with the "old" bootstrap typeahead plugin:

$(".typeahead").eq(0).trigger("keyup");

Haven't tested with IE unfortunately... Don't know about the new typeahead plugin...

Briannebriano answered 7/11, 2013 at 16:15 Comment(0)
O
2

Here's a simplified version of @Sam_Butler's work: http://jsfiddle.net/rimian/hrnf9

<button type="button" id="button">Crick</button>
<input type="text" id="text" class="typeahead">

Javascript:

$('#button').click(function() {
  $("#text").focus().typeahead('val', 'London');
});

// instantiate the bloodhound suggestion engine
var locations = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    remote: {
        url: 'https://maps.googleapis.com/maps/api/geocode/json?address=%QUERY&components=country:GB&sensor=false&region=uk', //add key
        filter: function (locations) {
            return $.map(locations.results, function (location) {
                return {
                    value: location.formatted_address
                };
            });
        }
    }
});

locations.initialize();

$('#text').typeahead(null, {
    name: 'value',
    displayKey: 'value',
    source: locations.ttAdapter()
});
Office answered 13/6, 2014 at 3:51 Comment(1)
This worked great for me. I already had a value in the text field so i just saved that in a var, emptied the val in typeahead and then set the prev value again and it opened the search. Maybe a hack but works fine.Garnierite
J
1

Be careful with this!

For those who are thinking about trigger typeahead behavior manually (on a button click for example) I strongly recommend you to don't do this.

I came for this solution and I lost almost an entire day making workarounds to it work properly (in my case that was a button click).

For those who really want go by this dark way, I share with you my ugly code that makes it work:

//Removes default features of typeahead
//This means that typeahead will not work like an "autocomplete", it only will be trigged when the user Click in #btnSearch button!
var txt = $("#typeahead");
//Save input events in variables (we'll need them)
eventInput = $._data(txt[0], "events").input[0];
eventBlur = $._data(txt[0], "events").blur[1];
//Remove input events
txt.unbind("blur");
txt.unbind("input");

//Set click event that triggers typeahead features manually
$("#btnSearch").click(function () {
    //Clears the cache of engine for it call ajax again, without it when the term was already searched the ajax is not called!
    engine.clearRemoteCache();

    txt.focus(); //When we click in a button, the focus from input is lost, so we set it again to not lose the behaviors of keyboard keys (up, down, tab, etc)
    txt.bind("input", eventInput); //Bind the event that we had saved
    txt.trigger("input"); //Trigger input (like the answer from @epascarello)
    txt.unbind("input"); //Removes it again 
});

//Set event on parent of the suggestion's div, this makes the sugestion div close when user click outside it
$("body").click(function () {            
    if (eventBlur != undefined) {
        if ($(".tt-dropdown-menu:visible").length > 0) {
            eventBlur.handler(); //This event closes the suggestion menu
        }
    }
});

Another thing that I did was change a code of the event "_checkInputValue" on typeahead.js. I change this:

areEquivalent = areQueriesEquivalent(inputValue, this.query);

to this:

areEquivalent = false;//areQueriesEquivalent(inputValue, this.query);

I set it to false because typeahead don't send two identical requests to server. This occur when the user clicks twice in the search button (I mean, when he searches more than once the same text that he has already searched for). Anyway, if you are using local data you won't need to do this.

Jewry answered 11/7, 2014 at 0:7 Comment(0)
Y
1

This worked for me.

$( document ).ready(function() {
    $('#the-basics .typeahead').typeahead({
      hint: false,
      highlight: true,
      minLength: 0
    },
    {
      name: 'states',
      displayKey: 'value',
      source: substringMatcher(states)
    });

    //set a value to input to trigger opening
    $(".typeahead").eq(0).val("a").trigger("input");
    //remove value for end user
    $(".typeahead").eq(0).val("");

});

See here for example: http://joshuamaynard.com/sandbox/autocomplete

Yount answered 3/9, 2014 at 0:25 Comment(1)
This works but is not perfect, when you select and after clicking again won't displayGelatinoid
K
1

The other answers were helpful but did not solve my problem. This solution does not involve customising any of the angular-ui code itself and serves the purpose of only triggering the typeahead to fetch results on an explicit button click.

To do this I had to overlay a text field on top of another (disabled) text field that is the actual one with the typeahead. Nobody will know the other one is there but it needs to be there for angular-ui to launch the menu in the correct location. You can't make it a hidden field because it will not be able to show the menu in the correct location.

The directive below will watch the typeaheadText and typeaheadTrigger variables to populate the disbled field when the button triggers this (by setting the trigger to true). The directive has isolated scope so it does not depend on anything other than passed in.

directive('typeaheadTrigger', function() {
  return {
    require: ["ngModel"],
    scope: {
      typeaheadText: '=',
      triggerFlag: '='
    },
    link: function(scope, element, attr, ctrls) {
      scope.$watch('triggerFlag', function(value) {
        if (scope.triggerFlag) {
          ctrls[0].$setViewValue(scope.typeaheadText);
          scope.typeaheadText = '';
          scope.triggerFlag = false;
        }
      });
    }
  };
})

The controller sets a few things up for this - the trigger and text scope variables inside an object. This demonstrates how to do it - ideally you'd wrap this whole thing in another directive so it can be used in your application while hiding the details.

Here's the plunk: http://plnkr.co/edit/UYjz6F5ydkMQznkZAlfx?p=preview

Kriemhild answered 9/10, 2014 at 4:3 Comment(0)
T
0

I used this to manually trigger a selection, when 1 item was in the tt-dataset. It just made sense to add this.

$("#mytypeahead").keyup(function (e) {
                var charCode = (typeof e.which === "number") ? e.which : e.keyCode;
                if (charCode == 13) {
                    if ($(this).parent().find(".tt-dataset").children().length == 1) {
                        //This is how we are submitting a single selection on enter key
                        $(this).parent().find(".tt-dataset").children(0).addClass("tt-cursor");
                        var kde = jQuery.Event("keydown");
                        kde.which = 13;
                        $(this).trigger(kde);                           
                    }    
                }                    
            });
Thorner answered 9/1, 2016 at 0:51 Comment(0)
E
0

I tried every method here but it was not working, only by using

$(".typeahead").val('hi').trigger('keyup');
$(".typeahead").val('hi').trigger('keydown');

The above code it worked for me. Don't know what exactly happened but using neither one worked only by using both it got worked.

Earflap answered 19/12, 2018 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.