Angular Material: md-autocomplete - 如何在 Enter 事件中隐藏 md-autocomplete-suggestions?
Angular Material: md-autocomplete - how to hide md-autocomplete-suggestions on Enter event?
我有 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
。
我用谷歌搜索发现:
$timeout( function() { $scope.$$childHead.$mdAutocompleteCtrl.hidden = true; },100);
但没有 $mdAutocompleteCtrl
(至少在我的 JS 中,仅在 HTML 中,我不知道它的范围)
我玩这个 example:输入 'a' 并在下拉菜单后按 Enter。
有什么想法吗?
$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;
};
TLDR:触发隐藏的示例代码 http://codepen.io/anon/pen/mJvGzp?editors=101
问题:
首先,"Angular Way" 建议应避免在 Controller 中操纵指令。控制器本质上应该只是检索(通过服务等)并提供构建视图所需的数据;它通常应该避免关心这些视图是如何实现的(即它应该不知道将使用什么指令)。这样做有多种充分的理由,其中之一可能是当您想要修改视图时,它会让生活变得更加轻松,例如换出指令。
如果确实需要手动修改指令,最好从另一个指令进行。这允许更大的灵活性,并简化以后的重构(相同的例子:如果换出不同的自动完成指令)。
此外,虽然这似乎是解决这种情况下问题的唯一方法,但 $scope.$$childHead.$mdAutocompleteCtrl.hidden
代码似乎相当老套 - 除非别无选择,否则应避免访问以 [= 开头的属性13=],并且还避免在不通过共享范围属性的情况下修改同级指令。
不幸的是,在深入研究源代码(在 master branch 上)之后,我找不到比(如您所建议的)抓住它的范围并修改 hidden
属性.
通过 Controller 访问它的另一个问题是它有点困难,因为它嵌套在其他几个范围内。您可以传递事件,获取 DOM 节点,然后拉起它的作用域,但控制器中有很多不相关的东西。
解决方法:
因此,我们可以添加同级指令,类似于您在 Codepen 示例中包含的 ngEnter
示例指令。也许更明确一点,这样它在做什么就更明显了:
.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
访问控制器方法的更好方法是定位元素,然后使用 jqLite 对象来访问控制器:
var $acElement = angular.element(document.getElementById('Auto'));
var acCtrl = $acElement.controller('mdAutocomplete');
acCtrl.hidden = true;
每当您在 angular 元素上使用 scope()
方法访问任何内容时,如果您想禁用 angular 调试信息,您的实现将会中断。
如果您不介意在输入时失去对 md-autocomplete 输入元素的关注,您可以关闭 md-autocomplete 建议,而无需使用涉及扰乱内部 $mdAutocompleteCtrl
控制器的 hacky 方法。这取决于 md-autocomplete 在输入元素不再聚焦时自动隐藏建议。
- 将您的 md-autocomplete 元素包装在一个表单中(或使用像
ng-enter
这样的指令)并使用 md-input-id 向输入元素添加一个 ID
<form ng-submit="vm.handleFormSubmit()">
<md-autocomplete <strong>md-input-id="autocomplete"</strong> ...>
</md-autocomplete>
</form>
- 在
#autocomplete
输入元素上调用 blur()
handleFormSubmit() {
angular.element(document.querySelector('#autocomplete')).blur();
}
我认为这个解决方案更好,因为:
它使用指令而不是控制器。
它比其他给定的指令解决方案更简单。
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 ... ...>
我有 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
。
我用谷歌搜索发现:
$timeout( function() { $scope.$$childHead.$mdAutocompleteCtrl.hidden = true; },100);
但没有 $mdAutocompleteCtrl
(至少在我的 JS 中,仅在 HTML 中,我不知道它的范围)
我玩这个 example:输入 'a' 并在下拉菜单后按 Enter。
有什么想法吗?
$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;
};
TLDR:触发隐藏的示例代码 http://codepen.io/anon/pen/mJvGzp?editors=101
问题:
首先,"Angular Way" 建议应避免在 Controller 中操纵指令。控制器本质上应该只是检索(通过服务等)并提供构建视图所需的数据;它通常应该避免关心这些视图是如何实现的(即它应该不知道将使用什么指令)。这样做有多种充分的理由,其中之一可能是当您想要修改视图时,它会让生活变得更加轻松,例如换出指令。
如果确实需要手动修改指令,最好从另一个指令进行。这允许更大的灵活性,并简化以后的重构(相同的例子:如果换出不同的自动完成指令)。
此外,虽然这似乎是解决这种情况下问题的唯一方法,但 $scope.$$childHead.$mdAutocompleteCtrl.hidden
代码似乎相当老套 - 除非别无选择,否则应避免访问以 [= 开头的属性13=],并且还避免在不通过共享范围属性的情况下修改同级指令。
不幸的是,在深入研究源代码(在 master branch 上)之后,我找不到比(如您所建议的)抓住它的范围并修改 hidden
属性.
通过 Controller 访问它的另一个问题是它有点困难,因为它嵌套在其他几个范围内。您可以传递事件,获取 DOM 节点,然后拉起它的作用域,但控制器中有很多不相关的东西。
解决方法:
因此,我们可以添加同级指令,类似于您在 Codepen 示例中包含的 ngEnter
示例指令。也许更明确一点,这样它在做什么就更明显了:
.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
访问控制器方法的更好方法是定位元素,然后使用 jqLite 对象来访问控制器:
var $acElement = angular.element(document.getElementById('Auto'));
var acCtrl = $acElement.controller('mdAutocomplete');
acCtrl.hidden = true;
每当您在 angular 元素上使用 scope()
方法访问任何内容时,如果您想禁用 angular 调试信息,您的实现将会中断。
如果您不介意在输入时失去对 md-autocomplete 输入元素的关注,您可以关闭 md-autocomplete 建议,而无需使用涉及扰乱内部 $mdAutocompleteCtrl
控制器的 hacky 方法。这取决于 md-autocomplete 在输入元素不再聚焦时自动隐藏建议。
- 将您的 md-autocomplete 元素包装在一个表单中(或使用像
ng-enter
这样的指令)并使用 md-input-id 向输入元素添加一个 ID
<form ng-submit="vm.handleFormSubmit()">
<md-autocomplete <strong>md-input-id="autocomplete"</strong> ...>
</md-autocomplete>
</form>
- 在
#autocomplete
输入元素上调用blur()
handleFormSubmit() {
angular.element(document.querySelector('#autocomplete')).blur();
}
我认为这个解决方案更好,因为:
它使用指令而不是控制器。
它比其他给定的指令解决方案更简单。
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 ... ...>