【问题标题】:ng-minlength in directive not populated when invalid指令中的 ng-minlength 无效时未填充
【发布时间】:2014-09-04 20:55:40
【问题描述】:

我正在创建一个封装标签的输入指令和一些错误消息,但我遇到了 ng-minlength 和 ng-maxlength。问题是他们不会填充模型值,直到它是一个有效值,所以我的父作用域可以显示一个值而我的指令不显示,反之亦然。查看plunk 了解我的意思的示例。

解决这个问题的唯一方法是定义我自己的 minlength 和 maxlength 验证器吗?是否有某种方式配置此行为,以便始终填充模型?我想在我的指令中使用所有内置的验证器,所以毫无疑问这将是所有这些验证器的问题,我宁愿不重新定义它们。

HTML:

<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="app" ng-controller="Controller"> 
    <label>Outer scope 1</label>
    <input name="input1" type="text" ng-model="model1" ng-minlength="4"/>
    <br/>
    <label>Directive scope 1</label>
    <input-dir ng-model="model1" ng-minlength="0"></input-dir>
    <br/>
    <br/>
    <br/>

    <label>Outer scope 2</label>
    <input name="input3" type="text" ng-model="model2"/>
    <br/>
    <label>Directive scope 2</label>
    <input-dir ng-model="model2" ng-minlength="4"></input-dir>


  </body>

</html>

Javascript:

var app = angular.module('app', []);

app.controller('Controller', function($scope){
  $scope.model1 = "Model1";
  $scope.model2 = "Model2";
});

app.directive('inputDir', function(){
  return {
    restrict: 'E',
    template: '<input type="text" ng-model="model" ng-minlength="{{ minlength }}" />',
    scope: {
      model: '=ngModel',
      minlength: '=ngMinlength'
    }
  };
});

【问题讨论】:

  • 我猜viewvalue只有在有效状态下才会传递给模型
  • 是的,除了实现我自己的验证器之外,还有其他人对此有什么建议吗?

标签: angularjs angularjs-directive angularjs-scope


【解决方案1】:

对于遇到相同问题的其他人,我通过重新定义所有验证器解决了这个问题,除了现在它们在无效时返回值以便填充模型。只需包含 valueValidators 模块。这些验证器在 $error 对象上可用,如 vvminlength 等。

vv-validators.js

(function () {
    'use strict';

    var validators = {};
    validators.vvUrl = function(value){
        var urlRegex = new RegExp(/[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi);
        return urlRegex.test(value);
    }

    validators.vvEmail = function(value){
        var emailRegex = new RegExp(/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
        return emailRegex.test(value);
    }

    validators.vvMinlength = function(value, min){
        var huh = value.length >= parseInt(min);
        return min && value && huh;
    }

    validators.vvMaxlength = function(value, max){
        return max && value && value.length <= parseInt(max);
    }

    validators.vvMin = function (value, min) {
        return min && parseFloat(value) >= parseFloat(min);
    }

    validators.vvMax = function (value, max) {
        return max && parseFloat(value) <= parseFloat(max);
    }

    validators.vvPattern = function (value, pattern) {
        return pattern && new RegExp(pattern).test(value);
    }

    validators.vvFloat = function (value) {
        var floatRegex = new RegExp(/^\-?\d+((\.|\,)\d+)?$/);
        return floatRegex.test(value);
    }

    validators.vvInteger = function (value) {
        var integerRegex = new RegExp(/^\-?\d+$/);
        return integerRegex.test(value);
    }

    var app = angular.module('valuedValidators', []);

    var names = Object.keys(validators);
    names.forEach(function(name){
        app.directive(name, function(){
            return {
                restrict: 'A',
                require: 'ngModel',
                link: function (scope, element, attrs, controller) {
                    controller.$parsers.unshift(function (viewValue) {
                        var valid = true;
                        var attrValue = attrs[name];
                        var func = validators[name];
                        if (attrValue !== 'false') {
                            valid = func(viewValue, attrValue);
                            controller.$setValidity(name.toLowerCase(), valid);
                        }
                        return viewValue;
                    });
                }
            };
        });
    });
}());

【讨论】:

  • 谢谢,西蒙。您能否发布一个示例,说明您现在如何在指令中使用它?我同样试图在指令中封装标签、输入字段和验证消息,并且因为 Angular 强调模板级别而不是控制器或模型级别的验证,所以我很难弄清楚如何传递将特定字段的验证标准放入我的指令中,以便它“流经”到输入字段本身...
  • 嗨,Alex,您需要在指令范围内将 ngModel 指定为 '=',以便内部输入以两种方式绑定到外部范围上的值。您还必须确保您的模型是对象的属性,否则一旦修改它们,您将在内部范围内丢失对它们的引用。如果将控制器用作语法,则默认情况下会出现此行为。我已将我的指令定义以及模板和用法添加到此 Plunk。它不起作用,因为它依赖于我尚未发布的其他代码,但希望它有所帮助。 plnkr.co/edit/KuHmtktjv0dPgyV8cpb7?p=preview
  • 西蒙,感谢您的 Plunk。它确实有助于可视化您的方法。理想情况下,我可以在模型或控制器上指定验证属性,并为每个表单字段绑定到错误属性。问题是我需要为每个字段的每个验证都有一个自定义消息,并且可能无法像您提供的那样通用,隐藏在指令中。我是 Angular 的新手,但有很多 Ember 经验。我在 Ember 中使用了这个 mixin 来完成这个工作,它运行良好:github.com/dockyard/ember-validations
  • 嗨,Alex,如果你看看我那里的指令定义,你会发现你可以为每个验证器指定海关消息。例如 vv-minlength-msg="自定义"。 compile() 函数中的设置只是为了定义一些默认消息,以防不提供。是这个意思吗?
  • 如果您在 Plunk 中发布一些代码,我可以看一下。也许在一个新问题中?
【解决方案2】:

还有一个更简单的解决方案:使用两个文本区域。

第一个是草稿,第二个是要进行验证的模型。

<textarea name="message_body_draft" cols="47" rows="15" style="width: 100%;"
    ng-model="message_body_draft"
    ng-change="message_body=message_body_draft"></textarea>

<textarea name="message_body" style="width: 100%;" disabled ng-model="message_body"
    ng-minlength="100" required></textarea>

当用户写入第一个模型时,它会自动填充正确的模型(第二个模型)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多