简体   繁体   English

angularjs中的十进制验证指令

[英]decimal validation directive in angularjs

I wanted to create directive in angular that would display error message if entered value is not in valid format. 我想创建角度指令,如果输入的值格式无效,该指令将显示错误消息。 What I finally came with is: 我最终想到的是:

http://plnkr.co/edit/l2CWu8u6sMtSj3l0kdvd?p=preview http://plnkr.co/edit/l2CWu8u6sMtSj3l0kdvd?p=预览

app.directive('kbDecimalValidation', function ($parse, $rootScope, $compile) {
        return {
            restrict: 'E',
            scope: {
                inputFieldRef: '=?',
                kbModel: '=ngModel',
                kbRequired: '@required',
                inputName: '@'
            },
            template: '<span ng-form="kbDecimalValidationForm">' +
                        '<input ng-model="kbModel" ng-required="kbRequired" ' +
                            'size="6"' +
                            'ng-pattern="/^[0-9]+(\\.[0-9][0-9]?)?$/" ' +
                            '/>' +
                        '<div ng-show="!kbDecimalValidationForm[inputName].$valid && kbDecimalValidationForm[inputName].$error.required"' +
                            'style="color: red; font-weight: bold">Field is required</div>' +
                        '<div ng-show="!kbDecimalValidationForm[inputName].$valid && kbDecimalValidationForm[inputName].$error.pattern"' +
                            'style="color: red; font-weight: bold">Bad format format,<br />allowed: "0.00"' +
                        '</div>' +
                    '</span>',
            replace: true,
            priority: 50,
            controller: function($scope){
                $scope.$watch(
                        'kbDecimalValidationForm[inputName]',
                        function (value) {
                            $scope.inputFieldRef = value;
                });
            },
            compile: function (tElement, tAttrs, transclude) {
                if($.tempKbDecimalValidationGUID == undefined){
                    $.tempKbDecimalValidationGUID = 0;
                }
                var guidInputName = 'XXX' + ++$.tempKbDecimalValidationGUID + 'XXX';
                $(tElement).find('input').attr('name', guidInputName); //it is here to force angular to assign value to: $scope.kbDecimalValidationForm[guidInputName]
                                                                       //there is no expression in name, so angular won't add it to $$watchers
                return {
                    pre: function preLink($scope, iElement, iAttrs, controller) {
                        //$(iElement).find('input').attr('name', iAttrs.inputName); //it doesn't work if there is expression in inputName,
                                                                                    // expression will be evaluated later (after linkFunction) 
                                                                                    // and the name assigned here will be updated (re-parsed by angular watch)
                    },
                    post: function postLink($scope, iElement, iAttrs, controller) {
                        $scope.kbDecimalValidationForm[iAttrs.inputName] = $scope.kbDecimalValidationForm[guidInputName]; //rewrite value to make it available by parsed name
                        $(iElement).find('input').attr('name', iAttrs.inputName); //assign parsed name - GUID didn't contain expression, so it is not in $$watchers,
                                                                                  // so it won't be replaced by angular

                    }
                }
            }

        };
    });

but I'm sure it is not propper way to do it. 但我敢肯定这不是正确的方法。 I expirience a lot of problems with it. 我觉得有很多问题。 Can somebody tell me what is the propper way to achieve it? 有人可以告诉我实现该目标的正确方法是什么?

PS: The problem I'm facing right now with the above directive is: when I use it in ng-repeat, and reorder repeated source the directive does not work correctly. PS:我现在使用上述指令遇到的问题是:当我在ng-repeat中使用它时,并对重复的源进行重新排序时,该指令无法正常工作。 I suspect the problem is with my "hacking coding" (the tempKbDecimalValidationGUID, and $scope.kbDecimalValidationForm variables) 我怀疑问题出在我的“黑客编码”上(tempKbDecimalValidationGUID和$ scope.kbDecimalValidationForm变量)

For Angular 1.2.x, you will have to use the ngModel.$parsers and $formatters pipelines for validation. 对于Angular 1.2.x,您将必须使用ngModel.$parsers$formatters管道进行验证。 Angular 1.3 has the dedicated $validators and even $asyncValidators pipelines. Angular 1.3具有专用的$validators甚至$asyncValidators管道。 So the outline of a validation solution for 1.2.x would be: 因此,针对1.2.x的验证解决方案的概述为:

.directive("kbDecimalValidation", function() {
    function parseDecimal(value) {
        // implement the conversion from a string to number, e.g. (simpistic):
        var val = parseFloat(value);
        // return a number (for success), null (for empty input), or a string (describing the error on error)
    }

    function formatDecimal(value) {
        // format a number to a string that will be displayed; the inverse of parseDecimal()
        // throw error if something goes wrong
    }

    return {
        restrict: "A",
        require: "ngModel",
        link: function(scope, elem, attrs, ngModel) {
            ngModel.$parsers.push(function(value) {
                var val = parseDecimal(value);
                if( typeof val === "string" ) {
                    // an error occured
                    ngModel.$setValidity("kbDecimal", false);
                    // return undefined!
                }
                else {
                    ngModel.$setValidity("kbDecimal", true);
                    return val;
                }
            });

            ngModel.$formaters.push(function(value) {
                if( value == null || typeof value === "number" ) {
                    ngModel.$setValidity("kbDecimal", true);
                    try {
                        return formatDecimal(value);
                    }
                    catch(e) {
                        ngModel.$setValidity("kbDecimal", false);
                        return "";
                    }
                }
                else {
                    ngModel.$setValidity("kbDecimal", false);
                    return "";
                }
            });
        }
    };
})

Many details will need work, but hopefully you get the idea. 许多细节都需要工作,但希望您能理解。 The parseDecimal() / formatDecimal() functions could even go to a dedicated Angular service, if they become too complex, or need to be reusable. 如果parseDecimal() / formatDecimal()函数变得过于复杂或需要可重用,它们甚至可以使用专用的Angular服务。


About the display of error messages 关于错误消息的显示

A quick and dirty way is to use DOM manipulation through the elem argument of link() . 一种快速而肮脏的方法是通过link()elem参数使用DOM操作。 Eg: 例如:

link: function(scope, elem, attrs, ngModel) {
    ...
    scope.$watch(
        function() { return ngModel.$error.kbDecimal; },
        function(newval) {
            var container = elem.parent();
            // append or remove the message as necessary
            ...
        }
    );
}

Another way, less quick but more componentized is to make 2 more directives. 另一种方式,较慢但更组件化的是再增加2条指令。 One will be placed on the <span ng-form> element (the container), another will display the messages. 一个将放置在<span ng-form>元素(容器)上,另一个将显示消息。 The HTML would be like: HTML将像:

<span ng-form="..." validation-container>
    <input ... kb-decimal-validation />
    <validation-messages></validation-messages>
</span>

Both kbDecimalValidation and validationMessages will require the validationContainer ; 无论kbDecimalValidationvalidationMessages将需要validationContainer ; the controller of the validationContainer will have a method, called by the kbDecimalValidation , to get notified about the $error object. 该的控制器validationContainer将有一个方法,由被叫kbDecimalValidation ,以收到通知的$error对象。 It will also expose a copy of the $error object. 它还将公开$error对象的副本。 The validationMessages will $watch that object and display or hide the appropriate messages. validationMessages$watch对象,并显示或隐藏适当的消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM