23

I'm using angular-ui typeahead. How can I trigger the popup items when focus on the input box, not after typing.

3

4 Answers 4

5

I can attest to the issues associated with expanding the UX of the typeahead. While @ueq's solution works, it has trouble releasing focus/clicking. I suggest changing things, specifically how you trigger the open UX.

suggested changes

  • open on double click - this solves the issue of click-releasing in @ueq's answer
  • check for existing values so as not to overwrite the value - we don't want to accidentally overwrite existing data when we open, so check first then set to a non-valid value to trigger the open.
  • change the name of the directive.... go with something more descriptive - considering that ui.bootstrap has already changed their namespace moving from 13.x to 14.x it just makes sense to go with your own name. Since directives can represent both UI &/or UX, it makes sense to name your directive to something that other developers can later track down more easily.

why

When working with a typeahead, people have certain expectations of the UX. Clicking into an input and having something popup can be somewhat jarring and misdirecting. A single click or tab-focus into an input traditionally does nothing other than readying the input for keyboard interaction. A double click generally carries the expectation that something more will happen (e.g. double click a file & close from a select dialog vs. single click to select, then click "ok" to close).

In programming we often try to employ the separation of concerns paradigm to our code. But I think this could be applied also to this particular UX and UX in general. Let the single-click & tab-focusing do what they've done for years and utilize the double-click to expand the UX of the typeahead.

plunker - http://plnkr.co/edit/GGl6X4klzVLKLX62Itbh?p=preview

.directive('typeaheadClickOpen', function($parse, $timeout) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function($scope, elem, attrs) {
            triggerFunc = function(evt) {
                var ctrl = elem.controller('ngModel'),
                    prev = ctrl.$modelValue || '';
                if (prev) {
                    ctrl.$setViewValue('');
                    $timeout(function() {
                        ctrl.$setViewValue(prev);
                    });
                } else {
                    ctrl.$setViewValue(' ');
                }
            }
            elem.bind('dblclick', triggerFunc);
        }
    }
})
Sign up to request clarification or add additional context in comments.

4 Comments

Editing my answer and changing the name of the directive to typeaheadClickOpen wouldn't have made that much of a difference... Or am I missing something?
the name would not have made a difference functionally speaking I suppose. But you're triggering something on click, if you have an existing value, then you're erasing that value on the model. Also, in your plunkr, click anywhere outside of the dropdown once you've selected a value and note that the input value changes. Your blur handler is erasing the value and is unnecessary.
another reason to rename this @ueq is that not all typeaheads serve data on-demand. In many cases a typeahead fetches it's data asynchronously, and by using a different directive name, you can ensure that those that are asynch don't get the same treatment.
thanks for the explanation! +1 :) I'll update my answer as soon as I find time
2

Hi I had the same issue and with this github discussion I was able to figure it out: Setup a directive that calls $setViewValue like

.directive('typeahead', function () {
    return {
        require: 'ngModel',
        link: function (scope, element, attr, ctrl) {
            element.bind('click', function () {
                ctrl.$setViewValue(' ' );
            });
            element.bind('blur', function () {
                ctrl.$setViewValue('');
            });
        }
    };
});

and add it to your input:

<input type="text" [...] typeahead>

Result (I created a plkr: http://plnkr.co/edit/Si6tFK2AammZy1HqEQzA):

enter image description here

Hope that helps :)

2 Comments

The problem with this is that when the input field loses focus and the user focuses on the input field again, it doesn't show the old results, but starts a new search.
you could set the elements value to the last value + ' '
1

Use typeahead-min-length="0" if supported by your angular-ui version. Otherwise this will help you out:

directive('typeaheadOpenOnFocus', function ($timeout) {
       return {
        require: 'ngModel',
        link: function (scope, element, attr, ctrl) {
            element.bind('click', function () {
                var vv = ctrl.$viewValue;
                ctrl.$setViewValue(vv ? vv+' ': ' ' );
                $timeout(function(){ctrl.$setViewValue(vv ? vv : '');},10)
            });
        }
    };
})

and add typeahead-open-on-focus as attribute to your input element.

This will open the typeahead onfocus if it already has a value too. And it automatically reverts the viewvalue.

Comments

0

Inspired by the answer of Boem

You can try this for avoiding the issue of view rendering

app.directive('typeahead', function () {
return {
    restrict: "A",
    require: 'ngModel',
    link: function (scope, element, attr, ctrl) {
        element.bind('click', function () {                
            ctrl.$setViewValue('');
            ctrl.$render();
        });
    }
};});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.