包含ng-change延迟的angular指令
我有一个searchinput字段与ng-change绑定的查询函数。
<input ng-model="search" ng-change="updateSearch()">
然而,这对每个angular色都会发生太快。 所以我最终做了这样的事情:
$scope.updateSearch = function(){ $timeout.cancel(searchDelay); searchDelay = $timeout(function(){ $scope.requery($scope.search); },300); }
因此,请求仅在用户停止input后300毫秒内完成。 有没有解决scheme将其包装在指令中?
从1.3angular度来看,使用ngModelOptions可以更容易地完成:
<input ng-model="search" ng-change="updateSearch()" ng-model-options="{debounce:3000}"> Syntax: {debounce: Miliseconds}
为了解决这个问题,我创build了一个名为ngDelay的指令。
ngDelay增强了ngChange的行为,以支持所需的延迟行为,每当用户处于非活动状态时,都会提供更新,而不是每次按键。 诀窍是使用子范围,并将ngChange的值replace为包含超时逻辑的函数调用,并在父范围上执行原始expression式。 第二个技巧是将任何ngModel绑定移动到父范围(如果存在)。 这些更改全部在ngDelay指令的编译阶段执行。
这是一个小提琴,其中包含一个使用ngDelay的例子: http : //jsfiddle.net/ZfrTX/7/ (在mainguy和Ryan Q的帮助下,由我编写和编辑)
你可以在GitHub上find这个代码感谢brentvatne 。 谢谢布伦特!
为了快速参考,下面是ngDelay指令的JavaScript代码:
app.directive('ngDelay', ['$timeout', function ($timeout) { return { restrict: 'A', scope: true, compile: function (element, attributes) { var expression = attributes['ngChange']; if (!expression) return; var ngModel = attributes['ngModel']; if (ngModel) attributes['ngModel'] = '$parent.' + ngModel; attributes['ngChange'] = '$$delay.execute()'; return { post: function (scope, element, attributes) { scope.$$delay = { expression: expression, delay: scope.$eval(attributes['ngDelay']), execute: function () { var state = scope.$$delay; state.then = Date.now(); $timeout(function () { if (Date.now() - state.then >= state.delay) scope.$parent.$eval(expression); }, state.delay); } }; } } } }; }]);
如果有任何TypeScript的话,这里是使用DefinitelyTyped的angular度定义的TypeScript:
components.directive('ngDelay', ['$timeout', ($timeout: ng.ITimeoutService) => { var directive: ng.IDirective = { restrict: 'A', scope: true, compile: (element: ng.IAugmentedJQuery, attributes: ng.IAttributes) => { var expression = attributes['ngChange']; if (!expression) return; var ngModel = attributes['ngModel']; if (ngModel) attributes['ngModel'] = '$parent.' + ngModel; attributes['ngChange'] = '$$delay.execute()'; return { post: (scope: IDelayScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes) => { scope.$$delay = { expression: <string>expression, delay: <number>scope.$eval(attributes['ngDelay']), execute: function () { var state = scope.$$delay; state.then = Date.now(); $timeout(function () { if (Date.now() - state.then >= state.delay) scope.$parent.$eval(expression); }, state.delay); } }; } } } }; return directive; }]); interface IDelayScope extends ng.IScope { $$delay: IDelayState; } interface IDelayState { delay: number; expression: string; execute(): void; then?: number; action?: ng.IPromise<any>; }
这对我来说是完美的: JSFiddle
var app = angular.module('app', []); app.directive('delaySearch', function ($timeout) { return { restrict: 'EA', template: ' <input ng-model="search" ng-change="modelChanged()">', link: function ($scope, element, attrs) { $scope.modelChanged = function () { $timeout(function () { if ($scope.lastSearch != $scope.search) { if ($scope.delayedMethod) { $scope.lastSearch = $scope.search; $scope.delayedMethod({ search: $scope.search }); } } }, 300); } }, scope: { delayedMethod:'&' } } });
使用指令
在你的控制器中:
app.controller('ctrl', function ($scope,$timeout) { $scope.requery = function (search) { console.log(search); } });
在你看来:
<div ng-app="app"> <div ng-controller="ctrl"> <delay-search delayed-method="requery(search)"></delay-search> </div> </div>
我知道我迟到了,但希望这会帮助任何人仍然使用1.2。 预ng模型选项我发现这对我工作,因为ngchange不会触发时,值是无效的。
这是@ doug的答案略有变化,因为它使用ngKeypress不关心模型是什么状态。
function delayChangeDirective($timeout) { var directive = { restrict: 'A', priority: 10, controller: delayChangeController, controllerAs: "$ctrl", scope: true, compile: function compileHandler(element, attributes) { var expression = attributes['ngKeypress']; if (!expression) return; var ngModel = attributes['ngModel']; if (ngModel) { attributes['ngModel'] = '$parent.' + ngModel; } attributes['ngKeypress'] = '$$delay.execute()'; return { post: postHandler, }; function postHandler(scope, element, attributes) { scope.$$delay = { expression: expression, delay: scope.$eval(attributes['ngKeypressDelay']), execute: function () { var state = scope.$$delay; state.then = Date.now(); if (scope.promise) { $timeout.cancel(scope.promise); } scope.promise = $timeout(function() { delayedActionHandler(scope, state, expression); scope.promise = null; }, state.delay); } }; } } }; function delayedActionHandler(scope, state, expression) { var now = Date.now(); if (now - state.then >= state.delay) { scope.$parent.$eval(expression); } }; return directive; };