如何验证ng-form是否被触及

时间:2016-11-11 14:20:03

标签: javascript angularjs validation typescript

我创建了一个'包装器'指令,用作表单元素包装器。一个或多个输入可以包含在该指令中。

指令本身包含ng-form指令,因此我可以检查每个实例是否存在错误以及(ng-model)输入是否无效。

在我的包装模板中,我想添加一个'错误'上课时:

  • 一个或多个输入为$ invalid
  • AND:
    • 表单已提交
    • 一个或多个输入是$ touch

这是我当前的(剥离的)包装器指令:

export class FormElementWrapper {
    public transclude = true;

    public template = `
        <div ng-form="formElementWrapper"
             ng-class="{'has-error': showError }" ng-transclude>
        </div>
    `;

    public link = (scope, element, attrs) => {
        // custom keep track of touched
        var touched = false;

        var isSubmitted = function(): boolean {
            var form: any = scope.formElementWrapper;
            return form.$$parentForm.$submitted;
        };

        scope.$watch(() => {
            // show error when:
            // - one ore more inputs are invalid
            // - AND
            // -- form is touched
            // -- OR
            // -- parent form is submitted
            var submitted = isSubmitted();
            return scope.formElementWrapper.$invalid && (touched || submitted);
        }, (val) => {
            scope.showError = val;
        });

        // override $setPristine to reset the custom touched property
        var origPristine = scope.formElementWrapper.$setPristine;
        scope.formElementWrapper.$setPristine = () => {
            touched = false;
            origPristine();
        }

        // bind to blur events of all inputs
        element.on("blur", ":input", () => {
            touched = true;
        });
    }
}

问题:如何知道一个或多个元素是否被触及? ngFormController没有该属性。目前我对输入的blur事件具有约束力,但我可以想象使用ng-model的其他指令本身不必是输入。

1 个答案:

答案 0 :(得分:2)

你基本上可以使用对$pristine未触及的对位的否定。因此,您可以使用if(!form.$pristine)进行检查,然后表示已触及表单。

根据form.FormController docs,如果用户尚未与表单进行互动,则$pristineTrue

但是,如果您想将NgModelController.$touched扩展到FormController,只需在表单中添加$touched = true,当任何元素被模糊时。它可以通过使用与ngModel并发的指令来完成,并在元素被FormController.$touched事件触发时更改其blur值。

以下示例实现了此解决方案。

angular.module('app', [])
  .directive('ngModel', function() {
    return {
      restrict: 'A',
      require: ['^?form'],
      priority: 1000,
      link: function(scope, elem, attr, ctrls) {
        var ngFormCtrl = ctrls[0];

        if (ngFormCtrl) {
          elem.on('blur', function onBlurEvent() {
            scope.$apply(function() {
              ngFormCtrl.$touched = true;
              elem.off('blur', onBlurEvent);
            });
          });
        }
      }
    };
  })
  .controller('myController', function($rootScope) {

    var $ctrl = this;

    $ctrl.model = {
      name: 'lenny',
      age: 23
    };
  });

angular.element(document).ready(function() {
  angular.bootstrap(document, ['app']);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.js"></script>
<div ng-controller="myController as $ctrl">
  <form name="$ctrl.myForm" novalidate>
    <label>Name :
      <input name="test1" ng-model="$ctrl.model.name">
    </label>
    <label>age :
      <input name="test2" ng-model="$ctrl.model.age">
    </label>

    <label>{{ $ctrl.myForm.$touched ? 'Touched' : 'Untouched'}}</label>
  </form>
</div>