20

我有一个带ngModel绑定的文本框,如下所示:

<input type="text" ng-model="typing" />

和这个 texbox 的价值

value: {{ typing }}

我希望模型延迟在我打字时更新值。也许如果我在 500 毫秒内停止输入,模型将更新所有值(我在文本框中输入的所有内容)。我做了一些谷歌,但没有运气。任何人有任何想法吗?请帮忙。

编辑

这个Angularjs: input[text] ngChange 在值发生变化时触发并没有为我的情况提供解决方案。它在模糊后带来解决方案更新值,但我希望在停止输入后更新值,而不是模糊文本框。

编辑 2(答案)

对于 Angular 1.4 版,指令ngModelOptions对我来说很有用。我可以这样写<input ng-model="typing" ng-model-options="{ updateOn: 'default', debounce: {'default': 500, 'blur': 0} }" />来延迟更新值到默认模型 500 毫秒,如果失去焦点立即更新。

4

2 回答 2

30

处理这个问题的最简洁的方法可能是编写一个指令来包装<input>元素并添加延迟行为。这是我为相同目的编写的指令:

angular.module('MyModule')
    .directive('easedInput', function($timeout) {
        return {
            restrict: 'E',
            template: '<div><input class="{{externalClass}} my-eased-input" type="text" ng-model="currentInputValue" ng-change="update()" placeholder="{{placeholder}}"/></div>',
            scope: {
                value: '=',
                timeout: '@',
                placeholder: '@',
                externalClass: '@class'
            },
            transclude: true,
            link: function ($scope) {
                $scope.timeout = parseInt($scope.timeout);
                $scope.update = function () {
                    if ($scope.pendingPromise) { $timeout.cancel($scope.pendingPromise); }
                    $scope.pendingPromise = $timeout(function () { 
                        $scope.value = $scope.currentInputValue;
                    }, $scope.timeout);
                };
            }
        }
    });

该指令将在您的 HTML 中调用,如下所示:

<eased-input value="myValue" timeout="500" placeholder="Please enter text..." />

剖析指令:

超时服务

该指令使用 Angular 的$timeout服务来处理时间:它是调用的可注入、可模拟、惯用的替代方案setTimeout。该服务被注入到指令构造函数中。

属性

该指令接受三个属性valuetimeoutplaceholder

这里的value属性绑定到拥有封闭“上下文”的控制器范围内的变量。在这种情况下,它绑定到myValue,即绑定到$scope.myValue负责此代码的任何控制器。它具有双向绑定,由指令属性中的'='条目表示。scope这意味着当该指令更新时value,更改会传播到拥有该指令的控制器;因此,在指令内$scope.myValue更改时将更改。value

和属性具有单向绑定:指令从属性中读取它们的值但不改变它们timeoutplaceholder它们是有效的配置值。

HTML 模板

指令上的template属性显示了一旦 Angular 编译并链接它就会在其位置生成的 HTML。它基本上只是一个input具有一些特殊和不那么特殊属性的元素。输入框中的值绑定到currentInputValue指令$scopevia上的变量ng-model。输入框上的事件通过指令change绑定到update指令上的函数。$scopeng-change

链接功能

该过程的核心在于link指令上的函数:我们定义了一个update方法。如上所述,此方法绑定到change指令的 HTML 模板中的输入框事件。因此,每次用户更改框中的输入时,update都会调用。

此方法使用$timeout服务。它告诉$timeout服务等待timeout几毫秒,然后应用一个回调来设置$scope.value = $scope.currentInputValue. 这类似于调用setTimeout(function () {$scope.value = $scope.currentInputValue}, timeout).

$timeout调用返回一个承诺。我们可以通过调用来取消p等待$timeout执行的promise $timeout.cancel(p)。这就是update它的第一行所做的:如果我们有来自先前更改事件的承诺,我们会在创建新事件之前取消它。这意味着,如果我们有一个 500 毫秒的超时,并且更新被调用了两次,调用相隔 400 毫秒,我们将只有一个等待触发的承诺。

总体结果

承诺在解决时设置$scope.value = currentInputValue;即,它将“外部可见”value属性设置为具有输入框内容的值。只会在几毫秒的静止期后发生value变化——外部控制器只会看到变化,我相信这是你所追求的行为。valuetimeout

于 2013-08-05T04:01:06.997 回答
13

如果您可以在模型中使用第二个属性,则可以$scope.$watch与函数一起使用debounce

HTML

<input type="text" ng-model="typing" />
<input type="text" value="{{ typed }}" />

Javascript

$scope.$watch('typing', debounce(function() {
    $scope.typed = $scope.typing;
    $scope.$apply();
}, 500));

您可以编写自己的去抖动函数,或使用现有的。这里有一个很好的实现,或者,如果你碰巧使用了 undescore.js,那么你已经设置好了

这是一个jsFiddle示例。

更新: Angular 1.3 现在有一个内置的方式来消除用户输入的抖动:ngModelOptions

于 2013-08-05T04:40:51.397 回答