Angular JS - Automatically focus input and show ty

2019-01-07 11:01发布

I am using Angular JS - ui.bootstrap.typeahead:

I would like to click a button and focus an input field and automatically show the typeahead suggestion dropdown. I have a directive that automatically focuses the input field when the button is clicked. How can I show the dropdown automatically so the user can use the down arrow, or click, to quickly choose a user?

I have created a Plunker with the ui-bootstrap JS file editable for tinkering:

http://plnkr.co/edit/Z79LY0OYlwFc3wirjxol?p=preview

This is my full script:

<!doctype html>
<html ng-app="plunker">
  <head>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.2/angular.js"></script>
    <script src="ui-bootstrap-tpls-0.10.0.js"></script>
  </head>
  <body>

<script>
  angular.module('plunker', ['ui.bootstrap'])
  .directive('focusMe', function($timeout, $parse) {
    return {
        //scope: true,   // optionally create a child scope
        link: function(scope, element, attrs) {
            var model = $parse(attrs.focusMe);
            scope.$watch(model, function(value) {
                if(value === true) { 
                    $timeout(function() {
                        element[0].focus(); 
                    });
                }
            });

        }
    };
});
function TypeaheadCtrl($scope, $http) {

  $scope.selected = undefined;
  $scope.states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'];
  $scope.opened = false;

  $scope.open = function() {
    $scope.opened = true;
  }
  $scope.close = function() {
    $scope.opened = false;
  }
}

</script>
<div class='container-fluid' ng-controller="TypeaheadCtrl">

    <h4>How can I open the typeahead dropdown automatically when button is pressed?</h4>
    <p>I have a directive that automatically focuses on the field but I can't seem to automatically show the typeahead. Even adding down arrow key click support would be great.

    <br/><br/>

    <button class="btn btn-default" ng-show="!opened" ng-click="open()">Open Input and show typeahead!</button>
    <button class="btn btn-default" ng-show="opened" ng-click="close()">Close Input</button>
    <br/><br/>

    <input type="text"
    focus-me="opened"
    ng-show="opened"
    ng-model="selected" 
    typeahead="state for state in states | filter:$viewValue | limitTo:8" 
    class="form-control">


    <br/>
    <pre ng-show="opened">Model: {{selected | json}}</pre>


</div>
  </body>
</html>

11条回答
▲ chillily
2楼-- · 2019-01-07 11:41

typeahead-min-length="0" does the trick (I am using v0.4.0)

查看更多
狗以群分
3楼-- · 2019-01-07 11:47

I wanted the typeahead to open whenever my input element had focus. @yohairosen's solution didn't work for me on the latest version of Angular Bootstrap (Version: 1.0.3). Here's the solution that worked for me. It involved manually invoking the parser attached by ui-bootstrap-typeahead which populates the suggestions:

angular.module('app')
.directive('typeaheadFocus', function () {
  return {
      require: 'ngModel',
      link: function (scope, element, attr, ngModel) {
        element.bind('click', function () {
          ngModel.$parsers[0](ngModel.$viewValue);
        });
      }
    };
  };
});

This might be buggy because it assumes the parser added by ui-bootstrap-typeahead is the only one.

查看更多
仙女界的扛把子
4楼-- · 2019-01-07 11:48

I got solved this issue through a directive. When you uses this directive, shows the list without some filter then, you type your search to find an element.

angular.module('myapp')
.directive('typeaheadLikeSelect', 
['$parse',function($parse) {
    return {
        require: 'ngModel',
        link: function (scope, element, attr, ngModel){

            var aux_modelValue, aux_viewValue,
                modelGetter = $parse(attr.ngModel),
                modelSetter = modelGetter.assign;

            var noViewValue = function(){
              return
              ngModel.$$lastCommittedViewValue === undefined ||
              !ngModel.$$lastCommittedViewValue.trim();
            };

            var forceEvent = function(){
              ngModel.$setViewValue();
              ngModel.$viewValue = ' ';
              ngModel.$setViewValue(' ');
              ngModel.$render();
              scope.$apply();
              element.val(element.val().trim());
            };

            element.on('mousedown', function(e){
              e.stopPropagation();
              forceEvent();
            });

            element.on('blur', function(e){
              e.stopPropagation();
              if(aux_modelValue){
                modelSetter(scope, aux_modelValue);
                scope.$apply();
              }
            });

            scope.$watch(function () {
              return ngModel.$modelValue;
            }, function(newValue, oldValue){
              if(newValue || (!newValue && !oldValue))
                aux_modelValue = newValue;
            });

        }
    };
}]);

I leave a view code, to testing the above code.

<script type="text/ng-template" id="customTemplate.html">
      <a>
          <span ng-bind-html="match.label.description | uibTypeaheadHighlight:query"></span>
      </a>
</script>
    <div class="form-group has-feedback" ng-class="{'has-success':items.mymodel}">
            <input
                placeholder="typeahead"
                ng-model="items.mymodel"
                uib-typeahead="responses as responses for responses in getResponses($viewValue)"
                typeahead-template-url="customTemplate.html"
                typeahead-input-formatter="$model.description"
                typeahead-loading="loadingResponses"
                typeahead-no-results="noResponses"
                typeahead-editable="false"
                typeahead-on-select="changeItem($item)"
                class="form-control"
              required="required"
              typeahead-like-select>
              <div ng-show="noResponses">
                <i class="glyphicon glyphicon-remove"></i> No Results Found
              </div>

              <span ng-show="!items.mymodel" class="glyphicon glyphicon-search form-control-feedback" aria-hidden="true"></span>
              <span ng-show="items.mymodel" class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
          </div>
查看更多
劳资没心,怎么记你
5楼-- · 2019-01-07 11:48

What we'd want is to trigger('input') on the input element when it's focused.

The correct way to do it in Angular is to do it in a directive.

angular.module('app')    
.directive('showList', function() {
   return {
       restrict: 'A',
       link: function(scope, iEle) {
           iEle.focus(function() {
               iEle.trigger('input');
           });
       }
   };
});

Use this directive on the typeahead input element -

<input show-list uib-typeahead="state for state in states | filter:$viewValue" typeahead-min-length="0" class="form-control">
查看更多
【Aperson】
6楼-- · 2019-01-07 11:49

Updated:

I added the directive to github for easy updates and access. You can now install it as a dependency through bower.

Original post:

I came up with a pretty clean hack that does not require any changes to ui-bootstrap-tpls. The Idea is to use $setViewValue() to trigger the popup with a combination of a special filter comparator function.

In order to bypass the minLength check, $setViewValue() has to be set to a value longer than 1 so i'm using one space string. The role of the comparator function is to treat one space as a match to all items so they'll all show up when clicking on an empty input.

I created a simple directive:

angular.module('app')
.directive('typeaheadFocus', function () {
  return {
    require: 'ngModel',
    link: function (scope, element, attr, ngModel) {

      //trigger the popup on 'click' because 'focus'
      //is also triggered after the item selection
      element.bind('click', function () {

        var viewValue = ngModel.$viewValue;

        //restore to null value so that the typeahead can detect a change
        if (ngModel.$viewValue == ' ') {
          ngModel.$setViewValue(null);
        }

        //force trigger the popup
        ngModel.$setViewValue(' ');

        //set the actual value in case there was already a value in the input
        ngModel.$setViewValue(viewValue || ' ');
      });

      //compare function that treats the empty space as a match
      scope.emptyOrMatch = function (actual, expected) {
        if (expected == ' ') {
          return true;
        }
        return actual.indexOf(expected) > -1;
      };
    }
  };
});

Usage:

<input type="text" ng-model="selected" typeahead="item for item in items | filter:$viewValue:emptyOrMatch | limitTo:8" typeahead-focus >
查看更多
Deceive 欺骗
7楼-- · 2019-01-07 11:52

you can achieve by this code

 $scope.change = function() {
        var e = document.getElementById("test");
        var $e = angular.element(e);
        $e.triggerHandler('focus');
        $e.triggerHandler('input');
    }

change the test to your type-head ID

查看更多
登录 后发表回答