Angular Material:md-autocomplete - 如何在Enter事件中隐藏md-autocomplete-suggestions?

时间:2015-08-06 14:43:12

标签: angularjs angular-material

我有md-autocomplete

<md-autocomplete 
                         md-min-length="1"
                         ng-enter="presEnter();"
                         md-no-cache="true"                        
                         md-selected-item="selectedItem" 
                         md-search-text="searchText" 
                         md-items="item in querySearch(searchText)"
                         md-item-text="item.name" 
                         placeholder="Search for a vegetable">
          <span md-highlight-text="searchText">{{item.name}} :: {{item.type}}</span>
        </md-autocomplete>

带指令:ng-enter

我的目标:当用户按下Enter时,我想隐藏md-autocomplete-suggestions下拉列表

我从HTML中知道我需要以某种方式调用:$mdAutocompleteCtrl.hidden = true;但不知道如何在Controller中使用$mdAutocompleteCtrl

我用Google搜索并发现:

$timeout( function() { $scope.$$childHead.$mdAutocompleteCtrl.hidden = true; },100);

但没有$mdAutocompleteCtrl(至少在我的JS中,只在HTML中,我不知道它的范围)

我玩这个example:输入&#39; a&#39;在下拉列表后按Enter键。

有什么想法吗?

5 个答案:

答案 0 :(得分:20)

$mdAutocompleteCtrl作为自动填充范围的属性。

首先,您需要访问自动完成元素。一种方法是在自动填充上添加ID:

<md-autocomplete id='Auto'
                 md-min-length="1"
                 ng-enter="presEnter();"
                 md-no-cache="true"
                 md-selected-item="selectedItem"
                 md-search-text="searchText"
                 md-items="item in querySearch(searchText)"
                 md-item-text="item.name"
                 placeholder="Search for a vegetable">

然后您可以使用该元素来获取自动完成的内部范围。因为自动完成元素本身位于您提供的范围内,所以您需要获取其中一个自动完成元素元素的范围。

$scope.presEnter = function(e){
    var autoChild = document.getElementById('Auto').firstElementChild;
    var el = angular.element(autoChild);
    el.scope().$mdAutocompleteCtrl.hidden = true;
};

以下是一个工作示例:http://codepen.io/anon/pen/rVPZKN?editors=101

答案 1 :(得分:10)

TLDR:触发隐藏http://codepen.io/anon/pen/mJvGzp?editors=101

的示例代码

问题:

首先,“Angular Way”建议应避免在Controller中操纵指令。 Controller应该基本上只检索(通过服务等)并提供构建视图所需的数据;它通常应该避免关心这些视图的实现方式(即它应该知道不会使用哪些指令)。这有很多很好的理由,一个可能是当你想要修改视图时,它会让生活变得更加容易,例如交换指令。

如果指令确实需要手动修改,最好从另一个指令执行此操作。这允许更大的灵活性,并在以后简化重构(相同的示例:如果交换不同的自动完成指令)。

此外,虽然在这种情况下似乎是解决问题的唯一方法,但$scope.$$childHead.$mdAutocompleteCtrl.hidden代码看起来相当粗糙 - 除非没有其他选择,否则应避免访问以{{1}开头的属性并且还避免修改兄弟指令而不通过共享范围属性执行此操作。

不幸的是,在深入研究源代码(在master branch上)之后,我找不到任何更好的方法来触发隐藏功能而不是(如你所建议的)抓住它的范围并修改{{1} } property。

通过Controller访问它的另一个问题是它有点困难,因为它通过其他一些范围嵌套。你可以传递事件,获取DOM节点,然后调高它的范围,但这在Controller中是很多不相关的东西。

解决方案:

因此,我们可以添加一个兄弟指令,类似于您在Codepen示例中包含的$$示例指令。也许是一些更明确的东西,以便它更明显地在做什么:

hidden

HTML只会在相关时包含此指令:

ngEnter

以下是使用它进行修改的示例:http://codepen.io/anon/pen/mJvGzp?editors=101

答案 2 :(得分:4)

我认为这个解决方案更好,因为:

  • 它使用指令代替控制器。

  • 它比其他给定的指令解决方案更简单。

的Javascript

app.directive('closeOnEnter', function($compile) {
      return {
         restrict: 'A',
         require: 'mdAutocomplete',
         link: function(scope, element) {
            element.on('keydown keypress', function($event) {
               // 13: Enter
               if ($event.keyCode == 13) {
                  var eAcInput = this.getElementsByTagName('input')[0];
                  eAcInput.blur();
               }
            });
         },
      };
});

HTML

<md-autocomplete close-on-enter ... ...>

答案 3 :(得分:3)

访问控制器方法的更好方法是定位元素,然后使用jqLit​​e对象获取对控制器的访问权限:

var $acElement = angular.element(document.getElementById('Auto'));
var acCtrl = $acElement.controller('mdAutocomplete');
acCtrl.hidden = true;

每当您使用角度元素上的scope()方法访问任何内容时,如果您想要禁用角度调试信息,您的实现将会中断。

答案 4 :(得分:1)

如果你不介意在输入时失去对md-autocomplete输入元素的关注,你可以关闭md-autocomplete建议,而不使用涉及弄乱内部$mdAutocompleteCtrl控制器的hacky方法。这取决于md-autocomplete在输入元素不再聚焦时自动隐藏建议。

  1. 在表单中包装md-autocomplete元素(或使用类似ng-enter的指令)并使用md-input-id
  2. 向输入元素添加ID
    
      <form ng-submit="vm.handleFormSubmit()">
        <md-autocomplete md-input-id="autocomplete" ...>
        </md-autocomplete>
      </form>
    
    
    1. blur()输入元素
    2. 上调用#autocomplete
      
      handleFormSubmit() {
        angular.element(document.querySelector('#autocomplete')).blur();
      }