【问题标题】:AngularJS Validation ngModel undefinedAngularJS 验证 ngModel 未定义
【发布时间】:2016-02-08 17:06:57
【问题描述】:

我将表单验证从对 Web 服务调用的响应中动态添加到表单中。当调用返回时,它会告诉我的验证指令我需要向表单添加哪些验证。 (我这样做是因为我想在提交期间在服务器上重用相同的验证,就像我在客户端上所做的那样。)当唯一的验证是“必需”类型时,这非常有效。 我遇到的问题是当表单控件的模型值没有通过验证规则时,模型值就是“未定义”。因此,在提交表单时不会将任何内容发送到服务器以在服务器端进行验证。我确实意识到如果表单无效,我可以阻止表单提交,但是,我让服务器确定数据的有效性遇到了。

我可以做些什么来强制模型值成为“无效值”,无论它是否违反了验证规则?更好的建议?下面是我正在使用的指令的片段。

    //this directive should be put on an ng-form element and it will hide/show any validations set on each input
    .directive('formValidator', ['validatorService', function (vs) {
        return {
            restrict: 'A',
            require: '^form',
            link: function (scope, element, attrs, form) {

                function iterateOverErrorsObject(errors, func, ignorechecking) {
                    if (!func)
                        return;

                    //show any new errors
                    for (var key in errors) {
                        if (key.indexOf('__') == 0)
                            continue;

                        _.each(errors[key], function (obj) {
                            if (form[obj.$name] == obj || ignorechecking) { //ensure the obj is for the current form
                                var input = vs.findElementByName(element, obj.$name);
                                if (input.length > 0) {
                                    func(input, obj);
                                }
                            }
                        });
                    }
                }

                scope.$watch(function () { return form.$error; }, function (newval, oldval, scp) {
                    iterateOverErrorsObject(oldval, function (input, obj) {
                        vs.hideErrors(input);
                    }, true);
                    iterateOverErrorsObject(newval, function (input, obj) {
                        vs.showErrors(input, obj, form._attr);
                    });
                }, true);

                //something told the validator to show it's errors
                scope.$on('show-errors', function (evt) {
                    iterateOverErrorsObject(form.$error, function (input, obj) {
                        vs.showErrors(input, obj, form._attr);
                    });
                });

                scope.$on('hide-errors', function (evt) {
                    vs.hideAllErrors(form);
                });
            }
        };
    }])
    //this directive is to be put on the ng-form element and will dynamically add/remove validators based on the validations configuration
    //which comes back from the service call "Validate"
    .directive('dynamicValidators', ['$compile', function ($compile) {
        return {
            priority: 0,
            restrict: 'A',
            //require: 'ngModel',
            require: '^form',
            scope: {
                'validations': '=',
            },
            link: function (scope, element, attrs, ctrl) {
                (function (form, scp) {

                    // this will hold any information necessary to get the error message displayed
                    // **have to add the form because the ctrl gets recreated every time the form.$error changes
                    function setAttr(ctrl, key, value) {
                        if (!ctrl._attr)
                            ctrl._attr = {};
                        if (!form._attr)
                            from._attr = {};

                        ctrl._attr[key] = value;
                        var obj = form._attr[ctrl.$name] = {};
                        obj[key] = value;
                    };

                    scope.$watch('validations', function (nv, ov) {
                        form._attr = {};
                        //remove old validators
                        if (ov && ov.length > 0) {
                            _.each(ov, function (e) {
                                var fctrl = form[e.MemberNames[0]];
                                if (fctrl && fctrl.$validators) {
                                    delete fctrl.$validators[e.ErrorKey];
                                    //fctrl.$setValidity(e.ErrorKey, true);
                                    fctrl.$validate();
                                }
                            });
                        }

                        //add new validators
                        if (nv && nv.length > 0) {
                            _.each(nv, function (e) {
                                var fctrl = form[e.MemberNames[0]];
                                if (!fctrl)
                                    return;

                                if (e.ErrorKey == 'required') {
                                    setAttr(fctrl, e.ErrorKey, e.ErrorValue);
                                    fctrl.$validators[e.ErrorKey] = function (modelValue, viewValue) {
                                        if (modelValue instanceof Array)
                                            return modelValue.length > 0;
                                        else
                                            return modelValue !== '' && modelValue !== null && modelValue !== undefined;
                                    };
                                } else if (e.ErrorKey == 'alphanumeric') {
                                    setAttr(fctrl, e.ErrorKey, e.ErrorValue);
                                    fctrl.$validators[e.ErrorKey] = function (modelValue, viewValue) {
                                        return viewValue == null || (viewValue != null && /^[a-zA-Z0-9]*$/.test(modelValue));
                                    };
                                } else if (e.ErrorKey == 'min') {
                                    setAttr(fctrl, e.ErrorKey, e.ErrorValue);
                                    fctrl.$validators[e.ErrorKey] = function (modelValue, viewValue) {
                                        return modelValue === undefined || modelValue === null || modelValue === "" || modelValue >= e.ErrorValue;
                                    }
                                } else if (e.ErrorKey == 'max') {
                                    setAttr(fctrl, e.ErrorKey, e.ErrorValue);
                                    fctrl.$validators[e.ErrorKey] = function (modelValue, viewValue) {
                                        return modelValue === undefined || modelValue === null || modelValue === "" || modelValue <= e.ErrorValue;
                                    }
                                }

                                //make the validator fire to set the status of the validator
                                if (fctrl.$validators[e.ErrorKey])
                                    //fctrl.$setValidity(e.ErrorKey, fctrl.$validators[e.ErrorKey](fctrl.$modelValue, fctrl.$viewValue))
                                    fctrl.$validate();
                            });
                        }
                    });
                })(ctrl, scope);
            },
        }
    }]);

【问题讨论】:

  • 我不知道你所说的“强制模型值是'无效值'”是什么意思——但如果你在客户端和服务器上使用相同的验证规则,那么发送发送到服务器的无效表单是在浪费用户的时间。如果客户端验证失败,只需阻止提交即可。
  • (我意识到你说过你意识到你可以做到这一点,但是“让服务器确定所遇到数据的有效性”——但如果是这样的话,为什么还要在全部?)
  • 例子是这样的。输入必须是字母数字,但不是必需的。输入中的值“12-1”,如果在输入上设置了仅验证字母和数字,则模型值将是“未定义”(因为其中包含“-”)。客户端上的 $viewValue 仍将显示值“12-1”,尽管提交会发送“未定义”。有问题。服务器会说......哦,没有设置,所以当客户端说“12-1”无效并将输入模型设置为未定义时,它不是无效的。 --是的,我可以在客户端检查,但我必须在服务器端做同样的事情。
  • 据我所知,答案是“所以不要那样做”。如果您要进行足够的客户端验证来更改模型值,那么就一直这样做,并让用户有机会在提交之前纠正错误。如果您不打算这样做,那么根本不要进行客户端验证,因为它对您或用户没有任何好处。

标签: angularjs forms validation


【解决方案1】:

如果您仍想向服务器发送无效数据,可以使用 allowInvalid 选项和 ngModelOptions 指令:

<input type="text" name="userName"
         ng-model="user.name"
         ng-model-options="{ allowInvalid: true }" />

来自ngModelOptions 的文档:

模型更新和验证

ngModel 中的默认行为是将模型值设置为 undefined 当验证确定该值无效时。经过 将allowInvalid 属性设置为true,模型仍然是 即使值无效也会更新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-26
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-13
    相关资源
    最近更新 更多