AngularJS设置全局ngModelOptions

时间:2014-07-11 22:23:10

标签: angularjs configuration angular-ngmodel

更新ngModel(以及随后的验证)的默认行为是 change ;我想将其更改为 blur docs只能通过以下方式解释如何执行此操作:<ANY ng-model-options="{ updateOn: 'blur' }"></ANY>。我竟然通过源代码查看,但不知何故找不到 ngModelOptions ng-model-options (尽管文档中都出现了这些内容,源代码)。

5 个答案:

答案 0 :(得分:25)

虽然Jon / John编写的ngModel装饰器提供了一个很好的幕后解决方案,但还必须要注意,声明性地,ngModelOptions不需要在单个输入字段级别声明,可以在模块级别声明。

<body ng-app = "myApp" ng-model-options="{ updateOn: 'blur' }">

执行上述操作会使myApp模块中的所有输入字段继承ng-model-options。 如果需要,可以在特定输入字段中覆盖这些字段(例如,搜索过滤器)。

这个plunker演示了:http://plnkr.co/edit/2L1arGgHJwK82xVucJ4p?p=preview

答案 1 :(得分:23)

正如@Angad所提到的,您可以在任何元素上设置ng-model-options,它将应用于其所有后代。但是,问题是,如果你这样设置,无线电和复选框将按预期停止工作:

<body ng-app="myApp" ng-model-options="{ updateOn: 'blur' }">

可以通过向change添加clickupdateOn来规避这一点:

<body ng-app="myApp" ng-model-options="{ updateOn: 'change click blur' }">

如果您还想在输入后的某个延迟后更新,可以使用以下内容:

<body ng-app="myApp" ng-model-options="{ updateOn: 'keyup change click blur', debounce: { keyup: 500, click: 0, change: 0, blur: 0 } }">

我在Firefox,Chome,Internet Explorer(10,11)和Safari中测试了这些技术。如果您使用其他事件,请务必通过浏览器对其进行测试,例如在点击后直接在所有浏览器上点击<{1}},然后除了IE。

答案 2 :(得分:12)

这是一个非常好的问题所以我写得更加深入blog article about this。我提出的唯一真正的通用方法是装饰ngModel指令,因为它是真正使用ngModelOptions的指令。

如果查看ngModel指令的角度源,它有一个预链接函数,可以通过使用属性$ options在ngModelController上有效地设置ngModelOptions。注意$ options是在ngModelOptionsDirective中创建的,它实际上是ng-model-options属性的$ eval。

我们需要在ngModel dectorator中执行的操作是在此预绑定函数之后为此$ options属性添加默认值(如果未定义)。我在这里假设,如果开发人员在项目中明确设置了ngModelOptions,他们不希望它神奇地改变!因此,如果$ options属性未定义,我们将只设置默认值。

以下是代码:

(function (angular) {
'use strict';

angular.module('myAppOverridesModule').config(['$provide',
    function ($provide) {
        $provide.decorator('ngModelDirective', [
            '$delegate',
            function ($delegate) {
                var directive = $delegate[0],
                    link = directive.link,
                    shouldSetBlurUpdateEvent = function (nodeName, inputType) {
                        // The blur event is only really applicable to input controls so
                        // we want to stick with the default events for selects, checkboxes & radio buttons
                        return nodeName.toLowerCase() === 'textarea' ||
                               (nodeName.toLowerCase() === 'input' && 
                               inputType.toLowerCase() !== 'checkbox' && 
                               inputType.toLowerCase() !== 'radio');
                    };

                directive.compile = function () {
                    return function (scope, element, attrs, ctrls) {
                        var ngModelCtrl = ctrls[0];
                        link.pre.apply(this, arguments);

                        // if ngModelOptions is specified leave it unmodified as developer is explicitly setting it.
                        if (ngModelCtrl.$options === undefined && shouldSetBlurUpdateEvent(element[0].nodeName, element[0].type)) {
                            console.log('set');
                            ngModelCtrl.$options = {
                                updateOn: 'blur',
                                updateOnDefault: false
                            };
                        }

                        link.post.apply(this, arguments);
                    };
                };

                return $delegate;
            }
        ]);
    }
]);
}(angular));

更新:我已更新代码以忽略选择,复选框和&amp;单选按钮作为模糊事件不是它们的最佳更新事件。

答案 3 :(得分:5)

我修改了Jon Samwell的答案,因为我再也无法让他上班了。

这会覆盖ngModelDirective的编译功能,方法是存储对它的引用,然后返回pre / postLink函数w /对其原始文件的调用以及我们的额外覆盖代码。

享受!

app.config(function($provide) {

    $provide.decorator('ngModelDirective', function($delegate) {
        var directive = $delegate[0],
            link = directive.link,
            shouldSetBlurUpdateEvent = function (nodeName, inputType) {
              // The blur event is only really applicable to input controls so
              // we want to stick with the default events for selects, checkboxes & radio buttons
              return nodeName.toLowerCase() === 'textarea' ||
                    (nodeName.toLowerCase() === 'input' && 
                     inputType.toLowerCase() !== 'checkbox' && 
                     inputType.toLowerCase() !== 'radio');
                };

        // save a reference to the original compile function
        var compileFn = directive.compile;

        directive.compile = function () {   

            var link = compileFn.apply(this, arguments);

            return {
                pre: function ngModelPostLink(scope, element, attr, ctrls) {

                    if(!ctrls[2]) {
                        ctrls[2] = {};
                    }

                    var ngModelOptions = ctrls[2];

                    if (ngModelOptions.$options === undefined && shouldSetBlurUpdateEvent(element[0].nodeName, element[0].type)) {
                        ngModelOptions.$options = {
                            updateOn: 'blur',
                            updateOnDefault: false
                        };
                    }

                    link.pre.apply(this, arguments);
                },
                post: link.post
            };
        };

        return $delegate;
    });

});

答案 4 :(得分:2)

而不是使用

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

你可以使用

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

并将其应用于dom中的父元素,例如容器div。上面的debounce设置告诉Angular仅在500毫秒无活动后评估验证规则。

使用debounce这种方法优于使用blur,因为当应用于整个表单时,模糊会为广播和复选框带来问题。

debounce选项是一个整数值,它会导致模型更新延迟整数毫秒。它降低了$digest周期发生的频率,这导致js应用程序消耗更少的资源,并允许用户在应用验证规则之前输入时间。

YearOfMoo.com建议像这样使用模糊和去抖动

ng-model-options="{ debounce : { default : 500, blur : 0 } }"

现在,在用户模糊了字段后立即应用模型值和验证。这为blur事件设置了0 ms的等待时间。模糊覆盖默认值。