AngularJS设置全局ngModelOptions

jac*_*cob 26 configuration angularjs angular-ngmodel

更新ngModel(以及随后的验证)的默认行为正在改变 ; 我想把它改成模糊.该文档仅解释如何做到这一点上通过的情况下,逐案:<ANY ng-model-options="{ updateOn: 'blur' }"></ANY>.我甚至通过源代码查看,但不知何故找不到ngModelOptionsng-model-options(尽管文档中都出现了这些内容,这是从源代码中删除的).

Ang*_*gad 25

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

<body ng-app = "myApp" ng-model-options="{ updateOn: 'blur' }">
Run Code Online (Sandbox Code Playgroud)

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

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

  • 对于我们的团队,我们经常被'allowInvalid'的默认选项'false'烧毁.当我们意外地将模型属性设置为'undefined'时,如果确定无效(这对我们来说不直观),在应用程序级别设置它会节省很多问题. (2认同)

Mar*_*ijk 23

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

<body ng-app="myApp" ng-model-options="{ updateOn: 'blur' }">
Run Code Online (Sandbox Code Playgroud)

这可以通过添加规避changeclickupdateOn:

<body ng-app="myApp" ng-model-options="{ updateOn: 'change click blur' }">
Run Code Online (Sandbox Code Playgroud)

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

<body ng-app="myApp" ng-model-options="{ updateOn: 'keyup change click blur', debounce: { keyup: 500, click: 0, change: 0, blur: 0 } }">
Run Code Online (Sandbox Code Playgroud)

我在Firefox,Chome,Internet Explorer(10,11)和Safari中测试了这些技术.如果您使用其他事件,请务必在浏览器之间进行测试,例如change点击后无线电直接在除IE之外的所有浏览器上点火.


Jon*_*Jon 12

这是一个非常好的问题所以我写了一篇关于此问题的更深入的博客文章.我提出的唯一真正的通用方法是装饰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));
Run Code Online (Sandbox Code Playgroud)

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


Joh*_*ler 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;
    });

});
Run Code Online (Sandbox Code Playgroud)