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

时间:2021-01-02 03:38:49

This question already has an answer here:

这个问题在这里已有答案:

I have a textbox with ngModel binding, like this:

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

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

and value of this texbox

和这个texbox的价值

value: {{ typing }}

价值:{{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.

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

EDIT

编辑

This Angularjs: input[text] ngChange fires while the value is changing doesn'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.

对于角度版本1.4,指令ngModelOptions在我的情况下很有用。我可以像这样写以延迟更新默认值为500ms的值,如果失去焦点则立即更新。

2 个解决方案

#1


30  

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:

处理此问题的最简单方法可能是编写一个包含元素并添加延迟行为的指令。这是我为同一目的而写的指令:

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和占位符。

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属性中用'='表示。这意味着当该指令更新值时,更改将传播到拥有该指令的控制器;因此,$ scope.myValue将在指令内更改值时更改。

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.

超时和占位符属性具有单向绑定:指令从属性读取其值但不更改它们。它们是有效的配置值。

HTML Template

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.

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

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函数:我们定义了一个更新方法。如上所述,此方法绑定到指令的HTML模板中输入框的change事件。因此,每次用户更改框中的输入时,都会调用更新。

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服务等待超时毫秒,然后应用一个设置$ 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调用返回一个promise。我们可以通过调用$ timeout.cancel(p)来取消等待执行的$ timeout产生的promise p。这是更新在第一行中的作用:如果我们有来自先前更改事件的承诺,我们在创建新事件之前取消它。这意味着如果我们有例如500毫秒超时,更新被调用两次,调用400ms,我们只有一个等待触发的承诺。

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;即它将'向外可见'值属性设置为具有输入框内容的值。值只会改变 - 外部控制器只会看到值的变化 - 在超时毫秒的静止期后,我认为这是你所追求的行为。

#2


11  

If you're okay with having a second property in your model, you can use $scope.$watch together with a debounce function:

如果您在模型中拥有第二个属性,则可以使用$ scope。$ watch和去抖功能:

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.

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

Here's a jsFiddle example.

这是一个jsFiddle示例。

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

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

#1


30  

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:

处理此问题的最简单方法可能是编写一个包含元素并添加延迟行为的指令。这是我为同一目的而写的指令:

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和占位符。

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属性中用'='表示。这意味着当该指令更新值时,更改将传播到拥有该指令的控制器;因此,$ scope.myValue将在指令内更改值时更改。

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.

超时和占位符属性具有单向绑定:指令从属性读取其值但不更改它们。它们是有效的配置值。

HTML Template

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.

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

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函数:我们定义了一个更新方法。如上所述,此方法绑定到指令的HTML模板中输入框的change事件。因此,每次用户更改框中的输入时,都会调用更新。

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服务等待超时毫秒,然后应用一个设置$ 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调用返回一个promise。我们可以通过调用$ timeout.cancel(p)来取消等待执行的$ timeout产生的promise p。这是更新在第一行中的作用:如果我们有来自先前更改事件的承诺,我们在创建新事件之前取消它。这意味着如果我们有例如500毫秒超时,更新被调用两次,调用400ms,我们只有一个等待触发的承诺。

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;即它将'向外可见'值属性设置为具有输入框内容的值。值只会改变 - 外部控制器只会看到值的变化 - 在超时毫秒的静止期后,我认为这是你所追求的行为。

#2


11  

If you're okay with having a second property in your model, you can use $scope.$watch together with a debounce function:

如果您在模型中拥有第二个属性,则可以使用$ scope。$ watch和去抖功能:

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.

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

Here's a jsFiddle example.

这是一个jsFiddle示例。

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

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