【问题标题】:Angularjs validation behaves differently for 1.3.0 and 1.2.6Angularjs 验证对于 1.3.0 和 1.2.6 的行为不同
【发布时间】:2014-12-13 20:55:29
【问题描述】:

我希望创建一个自定义指令,它呈现为输入类型元素。该指令应该重用 angularjs 验证框架。以下是我创建的custom-input 指令:

<!doctype html>
<html ng-app="validationApp">
<body>
  <div class="container" ng-controller="ValidationController as validationController">
    <form name="myForm">
        {{employee | json}}
    <custom-input ng-required="true" ng-model="employee.name" name="employee.name" id="employeeName" ng-pattern="/^[0-9]{1,7}$/"/></custom-input>
    <span ng-show="myForm['employee.name'].$error.required">This is a required field</span>
    <span ng-show="myForm['employee.name'].$error.pattern">This is a invalid field</span>
    </form>
  </div>
  <script type="text/ng-template" id="/templates/customInput.html">
    <div>
        <input type="text" name="{{name}}" ng-model="newInput" id="{{id}}">
    </div>
  </script>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js"></script>
</body>

</html>

这个对应的javascript是:

angular.module('validationApp', [])
.controller("ValidationController", function(){

})
.directive("customInput", function(){
    return {
        restrict: "E",
        require : "ngModel",
        replace: "true",
        templateUrl : "/templates/customInput.html",
        scope : {
            id : "@", //bind id to scope
            name : "@" //bind name to scope
        },
        link: function(scope, element, attrs, ngModelCtrl){
            //When newInput is updated, update the model of original input
             scope.$watch('newInput', function(newValue){
                ngModelCtrl.$setViewValue(newValue);
            });

            //On first load, get the initial value of original input's model and assign it to new input's model
            ngModelCtrl.$render = function(){
                var viewValue = ngModelCtrl.$viewValue;
                if(viewValue){
                    scope.newInput = viewValue;
                }
            }
        }
    }
});

我正在尝试对此自定义输入应用 ng-required 和 ng-pattern 验证。我遇到了两个问题:

  1. 在 angularjs 1.2.6 中,我可以在 custom-input 中触发 ng-required 验证,但在 1.3.0 中,验证不会被触发。
  2. 我无法在两个版本中触发ng-pattern 验证。

我的理解是ngModelController 中的$setViewValue 将触发所有验证。上面是一个人为的例子,我的实际用例是创建一个自定义指令,为 SSN 呈现三个输入框。

以下分别是 1.2.6 和 1.3.0 的 plunker 链接:

Angularjs 1.2.6 Angularjs 1.3.0

【问题讨论】:

  • replace: true 参数现在已被弃用。避免使用它。
  • 使用 ng-form。表单不适用于嵌套表单。
  • 我没听懂你。我在这里看不到任何嵌套表单!

标签: angularjs angularjs-directive angularjs-validation


【解决方案1】:

在指令内的隔离范围内,尝试使用 '=' 而不是 '@' 绑定它

使用@,如果您需要在链接(ing)函数中使用值,则需要使用 attr.$observe('title', function(value) { ... })。例如, if(scope.title == "...") 不会像您期望的那样工作。请注意,这意味着您只能异步访问此属性。如果您只使用模板中的值,则不需要使用 $observe()。例如,模板:'{{title}}'。

有了 =,你就不需要使用 $observe。

(来自What is the difference between '@' and '=' in directive scope in AngularJS?)

angular.module('validationApp', [])
.controller("ValidationController", function(){

})
.directive("customInput", function(){
return {
    restrict: "E",
    require : "ngModel",
    replace: "true",
    templateUrl : "/templates/customInput.html",
    scope : {
        id : "=", //bind id to scope
        name : "=" //bind name to scope
    },
    link: function(scope, element, attrs, ngModelCtrl){
        //When newInput is updated, update the model of original input
         scope.$watch('newInput', function(newValue){
            ngModelCtrl.$setViewValue(newValue);
        });

        //On first load, get the initial value of original input's model and assign it to new input's model
        ngModelCtrl.$render = function(){
            var viewValue = ngModelCtrl.$viewValue;
            if(viewValue){
                scope.newInput = viewValue;
            }
        }
    }
}
});

【讨论】:

  • 我不知道为什么一个孤立的范围会在这里引起问题。我不希望我的自定义输入模型暴露给父范围。如果多次使用此自定义输入,它们将在范围内发生冲突。另外,我想知道为什么 1.2.6 和 1.3.0 之间有区别? ng-pattern 也没有被解雇。我假设 ng-pattern 只会针对input 标签而不是custom-tag 触发。
  • @Vaibhav 如果是这种情况,请使用 '=' 而不是 '@' 进行绑定
  • 感谢您的回复。我试着采纳你的建议。请在此处参考 plunker http://embed.plnkr.co/FwQFhu/preview。这仍然不能解决 1.3.0 与 1.2.6 的问题。如果我无法理解您的建议,您能否与我分享运行代码 sn-p。
【解决方案2】:
  1. 要让ng-required 工作,不要在内部输入表单的输入中使用相同的名称。我似乎在 Angular 1.3 中,这会覆盖已注册的 ngModelController 附加到您的 custom-input。

    所以指令的模板可以是

    <div>
      <input type="text" ng-model="newInput" id="{{id}}">
    </div>
    

    这可以在http://plnkr.co/edit/TqMkxV?p=preview 看到。

    (另外,不知道为什么这里需要 id...)

  2. 我认为(但我不确定)在 1.2.6 ngPattern 中仅适用于 input 元素,而在 1.3 中它是与 ngModel 集成的单独指令。另外,让它在 1.3 中工作

    • 使用pattern 而不是ng-pattern,即使文档建议ng-pattern 应该可以工作。
    • 如果您直接在模板中编写模式,请不要将其包装在 / ... / 中。所以正确使用它来寻找正好 5 位数字是pattern="^\d{5}$"。文档在这方面具有误导性。

      可以在http://plnkr.co/edit/1zSiJI?p=preview 看到您修改后的 1.3 示例,以及 pattern 的工作示例

在 cmets 之后编辑:

  1. 如果您确实希望名称出现在内部指令中,并且与父元素名称相同(例如,使用标准整页 POST 提交到服务器),您可以将其包装在名为 ngForm 中。这将确保其控制器不会覆盖范围内的父控制器。

    <div>
      <div ng-form name="customInput">
        <input type="text" ng-model="newInput" id="{{id}}" name="{{name}}">
      </div>
    </div>
    

    这可以在http://plnkr.co/edit/Jrk63A?p=preview看到

【讨论】:

  • 感谢您的回复。那我该如何复制这个名字呢?我的场景不是单页应用程序。我有传统的往返应用程序,其中数据使用输入名称发送到服务器。我尝试从自定义输入中删除名称并将其添加到内部输入标签中,但这似乎并没有在表单中注册它。我应该使用这里描述的动态名称http://stackoverflow.com/a/21337430/1014559 吗?
  • 如果您希望内部输入与父指令同名,我添加了一部分内容。
【解决方案3】:

根据文档(https://docs.angularjs.org/guide/migration), 正则表达式字符串用作 Angular 1.2 中 ng-pattern 的值。相比之下,1.3中使用的是正则表达式对象。

// 1.2
$scope.exp = '/abc/i'; //string

<input ng-pattern="{{exp}}" ...


// 1.3
$scope.exp = /abc/i; //regexp object

<input ng-pattern="exp" ...

这是我的自定义输入指令示例

角度 1.2.16:

http://jsfiddle.net/miyukiw/m03f2ymt/4/

角度 1.3.5:

http://jsfiddle.net/miyukiw/9d64oa1m/4/

我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-16
    • 1970-01-01
    • 2017-04-20
    • 2021-08-20
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多