angular指令封装了ng-change的延迟

Hom*_*man 25 angularjs angularjs-directive

我有一个搜索输入字段,其中包含与ng-change绑定的requery函数.

 <input ng-model="search" ng-change="updateSearch()">
Run Code Online (Sandbox Code Playgroud)

然而,这对每个角色来说都会过快.所以我最终做了类似的事情:

  $scope.updateSearch = function(){
    $timeout.cancel(searchDelay);
    searchDelay = $timeout(function(){
      $scope.requery($scope.search);
    },300);
  }
Run Code Online (Sandbox Code Playgroud)

因此,请求仅在用户停止输入后300ms进行.是否有任何解决方案将其包装在指令中?

sch*_*max 50

从角度1.3开始,使用ngModelOptions更容易实现:

<input ng-model="search" ng-change="updateSearch()" ng-model-options="{debounce:3000}">

Syntax:  {debounce: Miliseconds}
Run Code Online (Sandbox Code Playgroud)


Dou*_*oug 25

为了解决这个问题,我创建了一个名为ngDelay的指令.

ngDelay增强了ngChange的行为以支持所需的延迟行为,该行为在用户处于非活动状态时提供更新,而不是在每次击键时提供.诀窍是使用子范围,并将ngChange的值替换为包含超时逻辑的函数调用,并在父范围上执行原始表达式.第二个技巧是将任何ngModel绑定移动到父作用域(如果存在).这些更改都在ngDelay指令的编译阶段执行.

这是一个小提琴,其中包含一个使用ngDelay的例子:http: //jsfiddle.net/ZfrTX/7/(由我编写和编辑,在mainguy和Ryan Q的帮助下)

你可以在GitHub上找到这个代码,感谢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);
                        }
                    };
                }
            }
        }
    };
}]);
Run Code Online (Sandbox Code Playgroud)

如果有任何TypeScript游戏,这里是使用DefinitelyTyped的角度定义的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>;
}
Run Code Online (Sandbox Code Playgroud)

  • 我真的很喜欢这个指令,这正是我所需要的!无论如何,因为当页面上有多个输入时这不起作用,我允许自己在这里修改你的几个代码:restrict:'A',scope:true,compile:...看看这个分叉的小提琴看看我的意思:http://jsfiddle.net/ZfrTX/.再次感谢,我赞成你的回答!太糟糕了,它从未被接受过.我可以...... (2认同)
  • @RyanQ你是绝对正确的,并将其更改为隔离范围实际上修复了一个错误.查看更新的示例.不同的值不再局限于同一个对象,这让我感到困惑.我很困惑,因为我以为我正在使用隔离范围,而实际上我正在使用原型继承元素范围的那个.谢谢. (2认同)

Alb*_*orz 0

这对我来说非常有效: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:'&'
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

使用指令

在你的控制器中:

app.controller('ctrl', function ($scope,$timeout) {
    $scope.requery = function (search) {
        console.log(search);
    }
});
Run Code Online (Sandbox Code Playgroud)

在您看来:

<div ng-app="app">
    <div ng-controller="ctrl">
        <delay-search delayed-method="requery(search)"></delay-search>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)