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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18050099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 10:35:16  来源:igfitidea点击:

Angularjs: how to make input[text] ngModel delay valued while typing

javascriptangularjs

提问by Stiger

I have a textbox with ngModelbinding, like this:

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

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

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

and value of this texbox

和这个 texbox 的价值

value: {{ typing }}

value: {{ typing }}

I want the model delay to update value while i'm typing. Maybe if I stop type in 500ms, the model will update all value (all things I typed in textbox). I make some google but no luck. Anyong has any idea? please help.

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

EDIT

编辑

This Angularjs: input[text] ngChange fires while the value is changingdoesn't give solution for my case. It bring solution update value after blur, but I want the value update after stop typing, not blur textbox.

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

EDIT 2 (Answers)

编辑 2(答案)

With angular version 1.4, directive ngModelOptionsis useful in my case. I can write like this <input ng-model="typing" ng-model-options="{ updateOn: 'default', debounce: {'default': 500, 'blur': 0} }" />to delay update value to model 500ms in default and update immediately if lost focus.

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

回答by Peter

The tidiest way to handle this is probably to write a directive which wraps up the <input>element and adds the delaying behaviour. Here is a directive I wrote for the same purpose:

处理这个问题的最简洁的方法可能是编写一个指令来包装<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);
                };
            }
        }
    });

This directive would be called in your HTML like so:

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

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

Dissecting the directive:

剖析指令:

Timeout Service

超时服务

This directive uses angular's $timeoutservice to handle timing: it is an injectable, mockable, idiomatic alternative to calling setTimeout. This service is injected in the directive constructor.

该指令使用 angular 的$timeout服务来处理时间:它是调用setTimeout. 该服务被注入到指令构造函数中。

Attributes

属性

The directive accepts three attributes: value, timeoutand placeholder.

该指令接受三个属性:value,timeoutplaceholder

The valueattribute here binds to a variable on the scope of the controller which owns the enclosing 'context'. In this case it binds to myValue, i.e. to $scope.myValueon whichever controller is in charge of this code. It has a two-way binding, denoted by the '='entry in the scopeproperty of the directive. This means that when this directive updates value, the change is propagated up to the controller which owns the directive; hence, $scope.myValuewill change when valueis changed inside the directive.

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

The timeoutand placeholderattributes have one-way bindings: the directive reads their values from the attributes but does not alter them. They are effectively configuration values.

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

HTML Template

HTML模板

The templateproperty on the directive shows the HTML which will be generated in its place once Angular compiles and links it. It's basically just an inputelement with some special and not-so-special attributes. The value in the input box is bound to the currentInputValuevariable on the directive's $scopevia ng-model. The changeevent on the input box is bound to the updatefunction on the directive's $scopevia the ng-changedirective.

template有关该指令的显示性能,这将在它的位置,一旦角编译和链接它生成HTML。它基本上只是一个input具有一些特殊和不那么特殊的属性的元素。输入框中的值绑定到currentInputValue指令的$scopevia上的变量ng-model。该change输入框事件被绑定到update对指令的功能$scope通过ng-change指令。

Link function

链接功能

The guts of the process lie in the linkfunction on the directive: we define an updatemethod. As stated above, this method is bound to the changeevent of the input box within the directive's HTML template. Thus, every time the user changes the input in the box, updateis called.

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

This method uses the $timeoutservice. It tells the $timeoutservice to wait for timeoutmilliseconds, then to apply a callback which sets $scope.value = $scope.currentInputValue. This is similar to calling setTimeout(function () {$scope.value = $scope.currentInputValue}, timeout).

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

The $timeoutcall returns a promise. We are able to cancel a promise pproduced by $timeoutwhich is waiting to execute by calling $timeout.cancel(p). This is what updatedoes in its first line: if we have a promise from a previous change event, we cancel it before creating a new one. This means that if we have e.g. a 500ms timeout, and update gets called twice, with the calls 400ms apart, we will only have one promise waiting to fire.

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

Overall result

总成绩

The promise, when resolved, sets $scope.value = currentInputValue; i.e. it sets the 'outwardly visible' valueproperty to have the value of the contents of the input box. valuewill only change -- and external controllers will only see valuechange -- after a quiescent period of timeoutmilliseconds, which I believe is the behaviour you were after.

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

回答by Michael Benford

If you're okay with having a second property in your model, you can use $scope.$watchtogether with a debouncefunction:

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

HTML

HTML

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

Javascript

Javascript

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

You can write your own debounce function, or use an existing one. There's a good implementation here, or, if you happen to be using undescore.js, you're already set.

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

Here's a jsFiddleexample.

这是一个jsFiddle示例。

UPDATE:Angular 1.3 has now a built-in way to debounce user input: ngModelOptions.

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