【问题标题】:ng-model-options debounce not working on blur event as expected?ng-model-options debounce 不能按预期处理模糊事件?
【发布时间】:2017-07-11 18:23:23
【问题描述】:

我在input 上应用了ng-model-options,配置如下

ng-model-options="{updateOn:'default blur',debounce:{default:1000,blur:0}}"

根据ng-model-options 的应用配置,我期待ng-blur 事件上更新的ng-model's 值,但尽管为模糊事件设置了0 debounce 值,但它不会返回新值。

*注意:仅当用户在default debounce 中给定的时间之前集中注意力时才会出现此问题,即1000

HTML:

<input type="text" ng-model="myname" ng-blur="onBlur(myname)" ng-model-options="{updateOn:'default blur',debounce:{default:1000,blur:0}}">
<input type="text" ng-model="output"/>

JS:

$scope.myname = "Yogesh";
$scope.output = "";
$scope.onBlur = function(a){
   $scope.output = a;
}

Plunker 链接:https://embed.plnkr.co/XJMUUD/

为什么去抖不起作用?如果我做错了,请纠正我!

提前致谢:)

我也已经给出了我的问题的答案!让我知道它使用起来有多灵活,以及它如何帮助减少事件摘要周期。

【问题讨论】:

  • 请参考我提供的plunker!
  • 看起来第二个输入更新为以前的模型值,即使从ng-model-options 中删除debounce 就像ng-blur="onBlur(myname)" ng-model-options="{updateOn:'blur'}" 一样
  • 是的@StanislavKvitash 我也测试过。这意味着它的ng-model-options="{updateOn:'blur'}" 问题,实际上就像ng-model-options 指令中的错误。因为不必要地导致在指令或控制器中使用$timeout
  • 我昨天尝试调试它,它看起来像由ngBlur 创建的on("blur" 侦听器在视图值提交之前触发并且模型值由updateOn 更改听众。就像一种解决方法,我认为可以使用ngChange(因为它在模型实际更改时触发)而不是ngBlur
  • 如果您不想在默认值中添加change,您可以使用 JavaScript,仅用于输入 [type="text"]。 &lt;input type="text" ng-model="myname" ng-blur="onBlur($event.currentTarget.value)" ng-model-options="{updateOn:'default blur',debounce:{default:1000,blur:0}}"&gt;

标签: javascript angularjs angularjs-ng-model angularjs-events


【解决方案1】:

ng-model-options 如何帮助减少事件摘要周期?

是的,ng-model-options 可以帮助您限制$digest 循环的数量。如果您只使用 ng-model 而不为其设置任何选项,那么您的 $digest 循环将针对 ng-model 值的每次更改运行。如果$digest 循环充满了要进行脏检查的数据,则用户将在(例如)在 .Here 中输入时看到 UI 中的滞后。这是 toddmotto 的博客中引用的示例.

// app.js
angular
	.module('app', []);

function trackDigests($rootScope) {
    function link($scope, $element, $attrs) {
        var count = 0;
        function countDigests(newValue, oldValue) {
            count++;
            $element[0].innerHTML = '$digests: ' + count;
        }
        $rootScope.$watch(countDigests);
    }
    return {
        restrict: 'EA',
        link: link
    };
}

angular
	.module('app')
	.directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
    <div>
        <form name="myForm">
            <h3>Standard &lt;input&gt;</h3>
            <track-digests></track-digests>
            <input 
                   type="text" 
                   name="test" 
                   ng-model="test">
        </form>
    </div>
</div>

从我们的标准输入中可以看出,$digest 循环会针对我们在输入字段中键入的每个字符触发。这可能会导致大型应用程序的最终用户延迟。

现在我们将看到带有 ng-model 选项的输入的情况。

// app.js
angular
	.module('app', []);

function trackDigests($rootScope) {
    function link($scope, $element, $attrs) {
        var count = 0;
        function countDigests(newValue, oldValue) {
            count++;
            $element[0].innerHTML = '$digests: ' + count;
        }
        $rootScope.$watch(countDigests);
    }
    return {
        restrict: 'EA',
        link: link
    };
}

angular
	.module('app')
	.directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
    <div>
        <form name="myForm">
            <h3>ngModelOptions &lt;input&gt;</h3>
            <track-digests></track-digests>
            <input 
                   type="text" 
                   name="test" 
                   ng-model="test"
                   ng-model-options="{
                       updateOn: 'blur'
                   }">
        </form>
    </div>
</div>

在这里我们可以看到$digest 循环只有在我们失去输入焦点时才会被触发。所以,基本上ngModelOptions 让我们可以控制$digest 循环发生的方式和时间。

让我们通过引入 debounce 来更好地控制 $digest 循环,以便我们可以告诉 angular 何时更新。

// app.js
angular
	.module('app', []);

function trackDigests($rootScope) {
    function link($scope, $element, $attrs) {
        var count = 0;
        function countDigests(newValue, oldValue) {
            count++;
            $element[0].innerHTML = '$digests: ' + count;
        }
        $rootScope.$watch(countDigests);
    }
    return {
        restrict: 'EA',
        link: link
    };
}

angular
	.module('app')
	.directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
    <div>
        <form name="myForm">
            <h3>ngModelOptions &lt;input&gt;</h3>
            <track-digests></track-digests>
            <input 
                   type="text" 
                   name="test" 
                   ng-model="test"
                   ng-model-options="{
                       updateOn: 'default blur',
                       debounce: {
                           'default': 250,
                           'blur': 0
                       }
                   }">
        </form>
    </div>
</div>

上面说明了默认值将在事件停止后 250 毫秒更新,并且当用户离开输入时模糊会立即更新(如果这是我们想要的行为)。

再次开始输入,然后停下来,注意$digest 计数大大低于最初的演示。然后,您可以单击/制表立即呼叫另一个$digest


debounce 的默认值和更改有什么区别?

去抖动对象属性的默认值和更改只是事件。默认不是 DOM 事件,这只是 ng-model-options api 的一部分。假设你正在设置你的 ngModelOptions 像

ng-model-options="{
  updateOn: 'default'
}"

那么您的输入字段的行为将不会从默认行为发生变化。在我们将它与 debounce like 结合使用之前,此配置并不是真正有用的

ng-model-options="{
  updateOn: 'default',
  debounce: { 'default': 500 }
}"

这将使输入在 500 毫秒后更新。所以基本上这回答了默认值是什么。您可以使用其他 DOM 事件(例如 change,blur,mouseover...等)进行反跳。


更新

当您使用ng-model-options="{updateOn:'default blur',debounce:{default:1000,blur:0}}" 时,ng-blur 被 ng-model 的旧值触发,之后仅触发 updateOn 事件。所以基本上输出将包含 ng-model 的旧值,尽管我的名字将被更新。

工作示例https://plnkr.co/edit/2JPHXvXd992JJ0s37YC9?p=preview

现在,当您使用ng-model-options="{updateOn:'default change blur',debounce:{default:1000,blur:0,change:0}}" 时,ng-blur 被 ng-model 的新值触发,因为设置 change:0 使得 updateOn 事件在 ng-blur 之前触发。所以基本上输出更新为ng-model 的新值以及 myname。

工作示例https://plnkr.co/edit/9wdA0he2YVcsPRLJ1Ant?p=preview

【讨论】:

  • 以上ng-model-options="{updateOn:'default blur',debounce:{default:250,blur:0}}"不会立即更新ng-model!你可以检查!
  • 不,它不会,它只会在 250 毫秒后更新,或者如果您将焦点移出输入。
  • 其实我想说...它不会在ng-blur 事件上立即更新ng-model。我希望我的ng-modelng-blur 事件上立即更新。这没有发生!
  • 我以为您已经找到了解决方案。你想知道它是如何灵活使用的,以及它将如何帮助减少事件摘要周期。以及默认和 debounce 变化有什么区别
  • 如果您想更新值,请使用 ng-change,因为如果您不等待 1 秒,ng-blur 将使用旧值触发。检查plnkr.co/edit/ZnF411h5z08NDr7OdK3e?p=preview
【解决方案2】:

经过一番研究,我们发现了这个配置

ng-model-options="{updateOn:'default change blur',debounce:{default:1000,blur:0,change:0}}"

效果很好!正如ng-blur 事件所预期的那样,它返回更新的值。

【讨论】:

    【解决方案3】:

    这是因为当您设置debounce 时,摘要循环会在给定时间后触发。触发摘要循环后,它会检查一个尚未在应用程序中同步的值是否发生了变化。

    在您的情况下,输入值将在 1000 毫秒或 1 秒后与模型变量 myname 同步,但在移除焦点时会立即更新。您的方法onBlur(myname) 是用myname 的先前值调用的,因为在调用函数时它仍然具有传递给它的参数的先前值(它无法更新myname 的值并调用函数) 然后摘要循环更新myname。 您可以通过将{{myname}} 放在输入旁边来检查模型是否立即更新。

    ng-blur 
       -> call onBlur(myname)
          -> here myname is with old value still
          -> trigger digest loop (here is where the new value is assigned to myname) 
             -> update model & view
    

    {updateOn: 'event'} 指定绑定应该在特定事件发生时发生。

    要在您的元素失去焦点(onblur)之前更新模型,您必须使用 updateOn: change 并将其时间设置为 0,这就是每次更改 angular 时如何立即将新值绑定到您的函数参数。

    【讨论】:

    • 感谢您的回复!!但是模糊的 0 debouce 值在这里是什么意思呢??
    • 这意味着我需要使用$timeout。基本上我希望我的工作应该在不使用$timeout 的情况下完成。你不认为这是错误吗?
    • 如果你想使用来自ng-model 的变量,你有ng-model-options 作为函数参数,是的,可能你必须使用$timeout。我不认为这是某种错误,我认为这就是它的行为方式。
    • 好吧!对于小型应用程序,这种变化很小,但对于大型应用程序,需要随时更改,因此我们正在寻找最符合我们期望的解决方案:)。
    猜你喜欢
    • 2017-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-20
    • 2018-04-24
    • 2018-08-29
    • 2015-03-11
    • 2014-01-02
    相关资源
    最近更新 更多