angularjs中的十进制验证指令

时间:2014-10-22 14:22:57

标签: javascript angularjs angularjs-directive

我想在angular中创建指令,如果输入的值不是有效格式,则会显示错误消息。 我最终带来的是:

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

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

                    }
                }
            }

        };
    });

但我确信不是这样做的方式。我用它来解决很多问题。有人能告诉我实现它的方法是什么?

PS:我现在遇到的上述指令的问题是:当我在ng-repeat中使用它时,并重新排序重复的源指令不能正常工作。我怀疑问题出在我的“黑客编码”(tempKbDecimalValidationGUID和$ scope.kbDecimalValidationForm变量)

1 个答案:

答案 0 :(得分:0)

对于Angular 1.2.x,您必须使用ngModel.$parsers$formatters管道进行验证。 Angular 1.3具有专用的$validators甚至$asyncValidators管道。因此, 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 "";
                }
            });
        }
    };
})

许多细节都需要工作,但希望你能得到这个想法。 parseDecimal() / formatDecimal()函数甚至可以转到专用的Angular服务,如果它们变得过于复杂,或者需要可重用。


关于显示错误消息

快速而肮脏的方法是通过elem的{​​{1}}参数使用DOM操作。 E.g:

link()

另一种方法,不那么快,但组件化程度更高的是另外两个指令。一个将放在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 ... } ); } 元素(容器)上,另一个将显示消息。 HTML就像:

<span ng-form>

<span ng-form="..." validation-container> <input ... kb-decimal-validation /> <validation-messages></validation-messages> </span> kbDecimalValidation都需要validationMessages; validationContainer的控制器将有一个方法,由validationContainer调用,以获得有关kbDecimalValidation对象的通知。它还将公开$error对象的副本。 $errorvalidationMessages对象并显示或隐藏相应的消息。