Angular JS - 自动聚焦输入并显示预先输入下拉菜单 - ui.bootstrap.typeahead

Hol*_*ley 34 angularjs angular-ui-bootstrap

我正在使用Angular JS - ui.bootstrap.typeahead:

我想单击一个按钮并聚焦输入字段并自动显示预先输入建议下拉列表.我有一个指令,当单击按钮时自动聚焦输入字段.如何自动显示下拉列表,以便用户可以使用向下箭头或单击,以快速选择用户?

我创建了一个带有ui-bootstrap JS文件的Plunker,可以修改:

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

这是我的完整脚本:

<!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>
Run Code Online (Sandbox Code Playgroud)

yoh*_*sen 55

更新:

我将指令添加到github以便于更新和访问.您现在可以通过bower将其安装为依赖项.

原帖:

我想出了一个漂亮干净的黑客工具,并没有要求任何修改UI的自举TPLS.想法是使用$ setViewValue()来通过特殊过滤器比较器功能的组合来触发弹出窗口.

为了绕过minLength检查,$ setViewValue()必须设置为大于1的值,所以我使用一个空格字符串.比较器功能的作用是将一个空格视为与所有项目匹配,这样在点击空输入时它们都会显示出来.

我创建了一个简单的指令:

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;
      };
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

用法:

<input type="text" ng-model="selected" typeahead="item for item in items | filter:$viewValue:emptyOrMatch | limitTo:8" typeahead-focus >
Run Code Online (Sandbox Code Playgroud)

  • @unTarm的解决方案不再适用于Angular 1.3+.但这很有效.谢谢 :) (3认同)
  • 我添加了一个`typeahead-min-length ="0"`并且替换了最后一个`$ setViewValue`来设置`viewValue || '''(例如'或'空字符串').这允许添加`| filter:$ viewValue`到typeahead,没有空格来触发值列表来干扰过滤. (2认同)

run*_*arm 21

正如HarishR在评论中提到的那样,此功能尚无内置支持.

但我只想尝试黑客攻击,结果如下:http://plnkr.co/edit/Qrnat8yTvISuM1qHHDlA?p = preview

它包含许多黑客,使其工作:

  1. 包含jQuery以便使用.trigger(),可以用原生JS替换,但我很懒.
  2. 使用ng-focus调用.trigger('input')来触发typehead弹出窗口
  3. 使用ng-trim ="false"禁用输入值自动修剪
  4. 一个自定义的empty-typeahead指令,它与ngModel的控制器交互,用于应用secretEmptyKey逻辑来绕过typeahead-min-length检查:

    .directive('emptyTypeahead', function () {
      return {
        require: 'ngModel',
        link: function (scope, element, attrs, modelCtrl) {
          // this parser run before typeahead's parser
          modelCtrl.$parsers.unshift(function (inputValue) {
            var value = (inputValue ? inputValue : secretEmptyKey); // replace empty string with secretEmptyKey to bypass typeahead-min-length check
            modelCtrl.$viewValue = value; // this $viewValue must match the inputValue pass to typehead directive
            return value;
          });
    
          // this parser run after typeahead's parser
          modelCtrl.$parsers.push(function (inputValue) {
            return inputValue === secretEmptyKey ? '' : inputValue; // set the secretEmptyKey back to empty string
          });
        }
      }
    })
    
    Run Code Online (Sandbox Code Playgroud)
  5. 一个自定义过滤器比较器函数,当一个参数是secretEmptyKey时,它始终返回true(显示所有结果):

    $scope.stateComparator = function (state, viewValue) {
      return viewValue === secretEmptyKey || (''+state).toLowerCase().indexOf((''+viewValue).toLowerCase()) > -1;
    };
    
    Run Code Online (Sandbox Code Playgroud)
  6. 删除limitTo过滤器以显示所有结果

  7. 如果内容太长,则设置max-height和overflow css属性以显示滚动条

完成!

  • 对于像我这样的开发人员来说,这是一个快速的注释,试图让这个工作:这个hack适用于Angular 1.2.x,1.3.x这似乎不再起作用了. (3认同)
  • @runTarm:解决方案似乎不再适用于Angular 1.3x.任何的想法?谢谢 (3认同)

Hen*_*Neo 12

我通过更改ui-bootstrap-tpls-0.10.0.js中的一些代码得到了一个有效的解决方案.因此,typeahead html标记没有区别.

您可以在http://plnkr.co/edit/LXHDpL?p=preview查看.

要使用此修复程序,请使用Plunk中的ui-bootstrap-tpls-0.10.0.js.要查看我的更改,请从Plunk中打开ui-bootstrap-tpls-0.10.0.js并搜索"ahneo".

 1. //minimal no of characters that needs to be entered before typeahead
    kicks-in
    // ahneo :: before
    //var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1;
    // ahneo :: after (changed minimal no of characters to 0 by default)
    var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 0;
 2. // ahneo :: new (set input value to empty string if it contains " " string value)
    if (inputValue === ' ') {
        inputValue = '';
        modelCtrl.$setViewValue('');
    }  
 3. // ahneo :: before
    //if (inputValue && inputValue.length >= minSearch) {
    // ahneo :: after (add new condition to get matches for min search = 0)
    if (minSearch === 0 || inputValue && inputValue.length >= minSearch) {
 4. // ahneo :: new (bind element to focus event to trigger modelCtrl.$parsers.unshift method)
    element.bind('focus', function (evt) {
        if (modelCtrl.$viewValue === '') {
            modelCtrl.$setViewValue(' ');
        }
    });
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助


Lyc*_*erg 6

现在,由于我没有足够的声誉来评论,我必须写一个新的答案,警告人们关于runTarm的答案.这是一个可行的解决方案,但它存在遇到以下错误的风险:

Error: [$rootScope:inprog] $apply already in progress
Run Code Online (Sandbox Code Playgroud)

这似乎是由于ng-focus是一个同步事件(见这里的讨论).相反,可以使用ng-click-attribute,并且不会发生此错误.

另外,我已经证实了这一点

$element.triggerHandler('input');
Run Code Online (Sandbox Code Playgroud)

与runTarm的答案中的jQuery触发器一样好用.


Cvu*_*nen 5

似乎内置的对此功能的支持即将在即将发布的版本中以typeahead-min-length属性支持值0 的形式出现.

它在主分支https://github.com/angular-ui/bootstrap/commit/d859f42cc022a5d8779f1c7b358486bbdd04ed57中的这个提交中实现,但是还没有发布它并且它不在0.14.x分支中.

希望新版本能够快速发布,以便不再需要这些变通方法.