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
Angularjs: how to make input[text] ngModel delay valued while typing
提问by Stiger
I have a textbox with ngModel
binding, 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 ngModelOptions
is 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 $timeout
service 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
, timeout
and placeholder
.
该指令接受三个属性:value
,timeout
和placeholder
。
The value
attribute 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.myValue
on whichever controller is in charge of this code. It has a two-way binding, denoted by the '='
entry in the scope
property 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.myValue
will change when value
is changed inside the directive.
value
此处的属性绑定到控制器范围内的变量,该变量拥有封闭的“上下文”。在这种情况下,它绑定到myValue
,即绑定到$scope.myValue
负责此代码的任何控制器。它具有双向绑定,由指令属性中的'='
条目表示scope
。这意味着当此指令更新时value
,更改将传播到拥有该指令的控制器;因此,$scope.myValue
将value
在指令内部更改时更改。
The timeout
and placeholder
attributes have one-way bindings: the directive reads their values from the attributes but does not alter them. They are effectively configuration values.
在timeout
和placeholder
属性具有单向绑定:该指令从属性读取它们的值,但不会改变它们。它们是有效的配置值。
HTML Template
HTML模板
The template
property on the directive shows the HTML which will be generated in its place once Angular compiles and links it. It's basically just an input
element with some special and not-so-special attributes. The value in the input box is bound to the currentInputValue
variable on the directive's $scope
via ng-model
. The change
event on the input box is bound to the update
function on the directive's $scope
via the ng-change
directive.
该template
有关该指令的显示性能,这将在它的位置,一旦角编译和链接它生成HTML。它基本上只是一个input
具有一些特殊和不那么特殊的属性的元素。输入框中的值绑定到currentInputValue
指令的$scope
via上的变量ng-model
。该change
输入框事件被绑定到update
对指令的功能$scope
通过ng-change
指令。
Link function
链接功能
The guts of the process lie in the link
function on the directive: we define an update
method. As stated above, this method is bound to the change
event of the input box within the directive's HTML template. Thus, every time the user changes the input in the box, update
is called.
该过程的核心在于link
指令上的函数:我们定义一个update
方法。如上所述,此方法绑定到change
指令的 HTML 模板中输入框的事件。因此,每次用户更改框中的输入时,update
都会调用。
This method uses the $timeout
service. It tells the $timeout
service to wait for timeout
milliseconds, 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 $timeout
call returns a promise. We are able to cancel a promise p
produced by $timeout
which is waiting to execute by calling $timeout.cancel(p)
. This is what update
does 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' value
property to have the value of the contents of the input box. value
will only change -- and external controllers will only see value
change -- after a quiescent period of timeout
milliseconds, 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.$watch
together with a debounce
function:
如果您可以在模型中使用第二个属性,则可以$scope.$watch
与debounce
函数一起使用:
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。