Подтвердить что ты не робот

Angular Материал: md-autocomplete - как скрыть md-autocomplete-предложения по событию Enter?

У меня 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;, но понятия не имею, как использовать $mdAutocompleteCtrl в контроллере.

Я googled и нашел:

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

но нет $mdAutocompleteCtrl (по крайней мере, в моем JS, только в HTML и я не знаю его области)

Я играю с этим пример: введите 'a', а после раскрывающегося списка нажмите Enter.

Любые идеи?

4b9b3361

Ответ 1

$mdAutocompleteCtrl помещается как свойство в область автозаполнения.

Сначала вам нужен доступ к элементу автозаполнения. Один из способов сделать это - поместить идентификатор в автозаполнение:

<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

Ответ 2

TL;DR: Пример кода, который вызывает скрытие http://codepen.io/anon/pen/mJvGzp?editors=101

Проблема (ы):

Во-первых, "Angular Way" предполагает, что следует избегать манипулирования директивами в вашем контроллере. Контроллер должен по существу просто извлекать (через службы и т.д.) И предоставлять данные, необходимые для построения представления; обычно следует избегать заботы о том, как реализуются эти представления (то есть, он должен знать, какие директивы не будут использоваться). Для этого существуют различные веские причины, возможно, это облегчает жизнь, когда вы хотите изменить представление, например, менять директивы.

Если директивы действительно нужно изменить вручную, лучше сделать это из другой директивы. Это позволяет повысить гибкость и упростить рефакторинг позже (в том же примере: если они заменяются для разных директив автозаполнения).

Кроме того, хотя в этом случае это единственный способ решить проблему, код $scope.$$childHead.$mdAutocompleteCtrl.hidden кажется довольно взломанным - если нет другого выбора, следует избегать доступа к свойствам, начиная с $$, а также избегать изменения директив sibling, не делая этого через общие свойства области.

К сожалению, после перехода в исходный код (в master branch) я не смог найти более удобный способ запуска функции hide, чем (как вы предположили), чтобы захватить его область действия и изменить свойство hidden.

Еще одна проблема с доступом к нему через контроллер - это немного сложнее, потому что он вложен в несколько других областей. Вы можете передать событие, захватить DOM node и вытащить его область действия, но в этом контроллере много нерелевантного материала.

Решение:

Поэтому вместо этого мы можем добавить директиву sibling, аналогичную директиве примера ngEnter, которую вы включили в пример Codepen. Возможно, что-то более явное, чтобы было более очевидно, что он делает:

.directive('mdHideAutocompleteOnEnter', function () {
    return function (scope, element, attrs) {
        element.bind("keydown keypress", function (event) {
            if(event.which === 13) {
                scope.$apply(function (){
                    scope.$$childHead.$mdAutocompleteCtrl.hidden = true; // $scope  modified to scope
                });

                event.preventDefault();
            }
        });
    };
});

HTML будет просто включать эту директиву, если это необходимо:

<md-autocomplete 
               md-hide-autocomplete-on-enter
               md-items="item in querySearch(searchText)"
               md-item-text="item.name">
     <span md-highlight-text="searchText">{{item.name}} :: {{item.type}}</span>
</md-autocomplete>

Вот пример, измененный с ним в действии: http://codepen.io/anon/pen/mJvGzp?editors=101

Ответ 3

Я думаю, что это решение лучше, потому что:

  • он использует директиву вместо контроллера.

  • это проще, чем другое заданное директивное решение.

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 ... ...>

Ответ 4

Лучший способ доступа к методам контроллера - нацелить элемент, а затем использовать объект jqLite для доступа к контроллеру:

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

Всякий раз, когда вы получаете доступ к чему-либо, используя метод scope() для элемента angular, ваша реализация будет разорваться, если вы когда-либо захотите отключить информацию об отладке angular.

Ответ 5

Если вы не возражаете потерять фокус на входном элементе md-autocomplete при вводе, вы можете закрыть предложения md-autocomplete, не используя хакерские способы, которые связаны с беспорядком с внутренним контроллером $mdAutocompleteCtrl. Это зависит от md-autocomplete, чтобы автоматически скрывать предложения, когда элемент ввода больше не сфокусирован.

  • Обмотайте элемент md-autocomplete в форме (или используйте директиву как ng-enter) и добавьте идентификатор к элементу ввода, используя md-input-id

  <form ng-submit="vm.handleFormSubmit()">
    &ltmd-autocomplete md-input-id="autocomplete" ...>
    </md-autocomplete>
  </form>

  1. Вызов blur() в элементе ввода #autocomplete

handleFormSubmit() {
  angular.element(document.querySelector('#autocomplete')).blur();
}