在 Angular.js 中使用 "ng-keyup" 向输入文本框添加去抖动
Adding debounce to an input text box with an "ng-keyup" in Angular.js
我有一个搜索框指令
// Define the search-box
alSH.directive('searchBox',[function(){
return {
restrict: 'E',
template: `
<input
placeholder="Search.."
class="search-box"
ng-keyup=search($evt)
ng-model="query"
ng-model-options="{ debounce: 1000 }"
/>`,
controller: function SearchBoxController($scope, helper) {
$scope.query = ''; //ng model
$scope.search = function() { //this calls in every keyup event
helper.setQuery($scope.query).search();
};
helper.setQuery('').search();
}
};
}]);
并且我尝试使用 ng-model-options="{ debounce: 1000 }"
但它仍然为每个击键发送网络请求而不更新 ng-model
可能是由于 ng-keyup
.
我发现这个 post 要求类似的东西,但我似乎不明白解决方案
我添加了一个 codepen 演示,其中包含我试图实现此行为的上述代码片段
理想情况下,我想限制由于每次击键而发送的后端调用的数量。知道如何实现吗?
您可以使用类似的模式来完成:
var debounceTimer = false;
$scope.search= function() {
// if there's already a timeout going, cancel the current one
if (debounceTimer) {
$timeout.cancel(debounceTimer);
}
// create a new timeout, do your thing when it ellapses
debounceTimer = $timeout(function() {
// ... your action goes here, only if calls are made with at least ONE second interval ...
helper.setQuery($scope.query).search();
},
// adjust your time interval accordingly
1000);
};
简答:使用 ng-change
而不是 ng-keyup
。
长答案:
通常使用ng-keyup是错误的,因为有很多方法可以修改输入值(例如drag-drop),而且有些键不会修改输入值,例如Esc 键。这就是为什么你应该始终小心使用 keyup 并更好地使用输入更改事件。
如果您使用 ng-model,您应该需要 ngModel 指令,注入并使用 ngModelCtrl。这就是 ng-change 为您所做的:https://github.com/angular/angular.js/blob/9bff2ce8fb170d7a33d3ad551922d7e23e9f82fc/src/ng/directive/ngChange.js
在简单的场景中,你不需要知道所有这些,你可以坚持使用 ng-change
+ ng-model-options
,对于非常特殊的情况,当 [=31= 时有一些奇怪的 debounce/throttle/whatever 逻辑] 可能性是不够的,你写自定义例如my-change
以类似方式工作的指令。
在使用 answer provided here 进行了一些测试后,我设法添加了去抖动。
我删除了 ng-keyup=search($evt)
但保留了 ng-model-options="{ debounce: 1000 }"
.
<input
placeholder="Search.."
class="search-box"
ng-model="query"
ng-model-options="{ debounce: 1000 }"
/>
然后在控制器中添加了一个监视程序,用于跟踪触发搜索功能的 $scope.query
变量。为了简单起见,我没有使用 newValue
和 oldValue
的值,但如果需要,也可以使用它们来实现额外的功能。 solved codepen
$scope.$watch('query', function (newValue, oldValue) {
$scope.search();
});
我有一个搜索框指令
// Define the search-box
alSH.directive('searchBox',[function(){
return {
restrict: 'E',
template: `
<input
placeholder="Search.."
class="search-box"
ng-keyup=search($evt)
ng-model="query"
ng-model-options="{ debounce: 1000 }"
/>`,
controller: function SearchBoxController($scope, helper) {
$scope.query = ''; //ng model
$scope.search = function() { //this calls in every keyup event
helper.setQuery($scope.query).search();
};
helper.setQuery('').search();
}
};
}]);
并且我尝试使用 ng-model-options="{ debounce: 1000 }"
但它仍然为每个击键发送网络请求而不更新 ng-model
可能是由于 ng-keyup
.
我发现这个 post 要求类似的东西,但我似乎不明白解决方案
我添加了一个 codepen 演示,其中包含我试图实现此行为的上述代码片段
理想情况下,我想限制由于每次击键而发送的后端调用的数量。知道如何实现吗?
您可以使用类似的模式来完成:
var debounceTimer = false;
$scope.search= function() {
// if there's already a timeout going, cancel the current one
if (debounceTimer) {
$timeout.cancel(debounceTimer);
}
// create a new timeout, do your thing when it ellapses
debounceTimer = $timeout(function() {
// ... your action goes here, only if calls are made with at least ONE second interval ...
helper.setQuery($scope.query).search();
},
// adjust your time interval accordingly
1000);
};
简答:使用 ng-change
而不是 ng-keyup
。
长答案:
通常使用ng-keyup是错误的,因为有很多方法可以修改输入值(例如drag-drop),而且有些键不会修改输入值,例如Esc 键。这就是为什么你应该始终小心使用 keyup 并更好地使用输入更改事件。
如果您使用 ng-model,您应该需要 ngModel 指令,注入并使用 ngModelCtrl。这就是 ng-change 为您所做的:https://github.com/angular/angular.js/blob/9bff2ce8fb170d7a33d3ad551922d7e23e9f82fc/src/ng/directive/ngChange.js
在简单的场景中,你不需要知道所有这些,你可以坚持使用 ng-change
+ ng-model-options
,对于非常特殊的情况,当 [=31= 时有一些奇怪的 debounce/throttle/whatever 逻辑] 可能性是不够的,你写自定义例如my-change
以类似方式工作的指令。
在使用 answer provided here 进行了一些测试后,我设法添加了去抖动。
我删除了 ng-keyup=search($evt)
但保留了 ng-model-options="{ debounce: 1000 }"
.
<input
placeholder="Search.."
class="search-box"
ng-model="query"
ng-model-options="{ debounce: 1000 }"
/>
然后在控制器中添加了一个监视程序,用于跟踪触发搜索功能的 $scope.query
变量。为了简单起见,我没有使用 newValue
和 oldValue
的值,但如果需要,也可以使用它们来实现额外的功能。 solved codepen
$scope.$watch('query', function (newValue, oldValue) {
$scope.search();
});