web-dev-qa-db-fra.com

Angular Matériel: md-autocomplete - comment cacher les suggestions de md-autocomplete sur l'événement Enter?

J'ai 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>

avec directive: ng-enter.

Mon objectif: Lorsque l'utilisateur appuie sur Enter Je souhaite masquer md-autocomplete-suggestions liste déroulante 

Je sais que depuis HTML, j’ai besoin d’appeler: $mdAutocompleteCtrl.hidden = true; mais je ne sais pas comment utiliser $mdAutocompleteCtrl dans Controller. 

J'ai googlé et trouvé: 

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

mais il n'y a pas de $mdAutocompleteCtrl (du moins dans mon JS, uniquement en HTML et je ne connais pas sa portée)

Je joue avec cet exemple : tapez 'a' et après le menu déroulant, appuyez sur Entrée.

Des idées?

12
snaggs

Le $mdAutocompleteCtrl est placé en tant que propriété sur la portée de la saisie semi-automatique.

Tout d'abord, vous devez avoir accès à l'élément autocomplete. Une façon de faire est de mettre un identifiant sur la saisie semi-automatique:

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

Vous pouvez ensuite utiliser cet élément pour obtenir la portée interne de la saisie semi-automatique. Étant donné que l'élément autocomplete lui-même se trouve dans la portée que vous avez fournie, vous souhaiterez obtenir la portée de l'un des éléments enfants de cette dernière.

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

Voici un exemple de travail: http://codepen.io/anon/pen/rVPZKN?editors=101

20
James

TLDR: Exemple de code qui déclenche hide http://codepen.io/anon/pen/mJvGzp?editors=101

Les problèmes):

Tout d’abord, la «Voie angulaire» suggère d’éviter de manipuler les directives de votre contrôleur. Le contrôleur doit essentiellement extraire (via Services, etc.) et fournir les données nécessaires à la création d’une vue; généralement, il faut éviter de se soucier de la manière dont ces vues sont mises en œuvre (c’est-à-dire qu’il ne doit pas savoir quelles directives seront utilisées). Il y a diverses bonnes raisons à cela. L'une d'entre elles est peut-être que cela simplifie la vie beaucoup plus facilement lorsque vous souhaitez modifier la vue, telle que l'échange de directives. 

Si les directives doivent vraiment être modifiées manuellement, il est préférable de le faire à partir d'une autre directive. Cela permet plus de flexibilité et simplifie la refactorisation ultérieurement (même exemple: si vous échangez des directives de complétion automatique différentes).

De plus, bien que cela semble être le seul moyen de résoudre le problème dans ce cas, le code $scope.$$childHead.$mdAutocompleteCtrl.hidden semble assez compliqué - à moins qu'il n'y ait pas d'autre choix, il faut éviter d'accéder aux propriétés commençant par $$, ainsi que de modifier les directives sœurs sans le faire via les propriétés de portée partagée. 

Malheureusement, après avoir fouillé dans le code source (sur la branche master ), je n’ai trouvé aucun moyen plus agréable de déclencher la fonction de masquage que (comme vous l’avez suggéré) de saisir sa portée et de modifier la propriété hidden.

Un autre problème pour y accéder via le contrôleur est que c'est un peu plus difficile car il est imbriqué dans quelques autres domaines. Vous pouvez transmettre l'événement, saisir le nœud DOM et extraire sa portée, mais il y a beaucoup de choses non pertinentes dans un contrôleur. 

La solution:

Au lieu de cela, nous pouvons ajouter une directive frère, similaire à la directive exemple ngEnter que vous avez incluse dans l'exemple Codepen. Peut-être quelque chose d'un peu plus explicite pour que ce que cela fait soit un peu plus évident:

.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();
            }
        });
    };
});

Le code HTML inclurait simplement cette directive, le cas échéant:

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

Voici l'exemple, modifié avec lui en action: http://codepen.io/anon/pen/mJvGzp?editors=101

10
DRobinson

Je pense que cette solution est meilleure parce que:

  • il utilise une directive à la place du contrôleur.

  • c'est plus simple que l'autre solution de directive donnée.

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
gilad mayani

Le meilleur moyen d'accéder aux méthodes du contrôleur consiste à cibler l'élément, puis à utiliser l'objet jqLite pour accéder au contrôleur:

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

Chaque fois que vous accédez à quelque chose à l'aide de la méthode scope() sur un élément angulaire, votre implémentation sera interrompue si vous souhaitez désactiver les informations de débogage angulaire.

3
smola

Si cela ne vous dérange pas de perdre le focus sur l'élément d'entrée md-autocomplete lors de la saisie, vous pouvez fermer les suggestions md-autocomplete sans utiliser des méthodes compliquées qui impliquent de jouer avec le contrôleur interne $mdAutocompleteCtrl. Cela dépend de md-autocomplete pour masquer automatiquement les suggestions lorsque l'élément en entrée n'est plus activé.

  1. Enveloppez votre élément md-autocomplete dans un formulaire (ou utilisez une directive telle que ng-enter) et ajoutez un ID à l'élément en entrée à l'aide de md-input-id

  <form ng-submit="vm.handleFormSubmit()">
    <md-autocomplete md-input-id="autocomplete" ...>
    </md-autocomplete>
  </form>
  1. Appelez blur() sur l'élément d'entrée #autocomplete 

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