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

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

在包装模板中,我想在以下情况下添加“错误”类:


一个或多个输入是$ invalid
和:


表格已提交
要么
触摸一个或多个输入



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

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的其他指令本身不必是输入。

最佳答案

基本上,您可以使用未触及的对数的负数$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>

09-25 17:00