Angularjs:如何在输入时输入[text] ngModel延迟值

时间:2013-08-05 03:15:57

标签: javascript angularjs

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

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

此texbox的值

value: {{ typing }}

我希望模型延迟在我输入时更新值。也许如果我停止输入500ms,模型将更新所有值(我在文本框中键入的所有内容)。 我做了一些谷歌,但没有运气。安永有什么想法?请帮忙。

修改

Angularjs: input[text] ngChange fires while the value is changing并未为我的案例提供解决方案。它会在模糊后带来解决方案更新值,但我希望在停止输入后更新值,而不是模糊文本框。

编辑2(答案)

对于角度版本1.4,指令ngModelOptions在我的情况下很有用。我可以这样编写<input ng-model="typing" ng-model-options="{ updateOn: 'default', debounce: {'default': 500, 'blur': 0} }" />来将更新值延迟到默认模型500ms并在失去焦点时立即更新。

2 个答案:

答案 0 :(得分: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绑定到指令$scope上的ng-model变量。输入框中的change事件通过update指令绑定到指令$scope上的ng-change函数。

链接功能

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

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

$timeout调用返回一个promise。我们可以通过调用p取消等待执行的$timeout生成的承诺$timeout.cancel(p)。这就是update在第一行中所做的事情:如果我们从之前的更改事件中得到承诺,我们会在创建新事件之前取消它。这意味着如果我们有例如500毫秒超时,更新被调用两次,相隔400毫秒的呼叫,我们只有一个承诺等待开火。

总体结果

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

答案 1 :(得分:11)

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

<强> 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));

您可以编写自己的去抖功能,也可以使用现有功能。有一个很好的实现here,或者,如果你碰巧使用了unexcore.js,you're already set

这是一个jsFiddle示例。

更新:Angular 1.3现在有一种内置的方式可以去除用户输入:ngModelOptions