如何将自定义输入指令及其父表单重置为$ pristine

New*_*Dev 5 angularjs angularjs-directive angularjs-ng-form angularjs-ng-model

我已经实现了一个自定义输入指令 - counter具有重置功能.该指令有require: "ngModel".

我复位指令的的原始状态ngModel$setPristine().不同$setDirty(),$setPristine()不触及$pristine父表单的状态.

问:如何"通知"父表单该指令不再"脏",以便父表单可以$pristine重置其状态?

请记住,只是调用form.$setPristine()是不够的,因为表单中可能还有其他"脏"控件,我的指令不会(也不应该)知道.

这是指令的链接功能:

link: function(scope, element, attrs, ngModel){

  var original;

  ngModel.$render = function(){
    original = scope.counter = ngModel.$viewValue;
  };

  scope.up = function(){
    ngModel.$setViewValue(++scope.counter);
  };

  scope.reset = function(){
    scope.counter = original;
    ngModel.$setViewValue(scope.counter);
    ngModel.$setPristine(); // this sets $pristine on the directive, but not the form
  };
}
Run Code Online (Sandbox Code Playgroud)

以下是它的使用方法:

<div ng-form="form">
  <counter ng-model="count"></counter>
</div>
Run Code Online (Sandbox Code Playgroud)

plunker

New*_*Dev 3

从 Angular 1.3.x 开始,没有内置解决方案。

form.$setPristine()在其所有子控件上设置原始状态。(链接到代码

ngModel.$setPristine()只设置 $pristine 本身(链接到代码

解决此问题的一种方法是创建一个与指令并存的指令form并劫持form.$setDirty以跟踪脏控件计数。这可能最好在预链接阶段完成(即在子控件开始注册自身之前)。

app.directive("pristinableForm", function() {
  return {
    restrict: "A",
    require: ["pristinableForm", "form"],
    link: function(scope, element, attrs, ctrls) {
      var me = ctrls[0],
        form = ctrls[1];
      me.form = form;
      me.dirtyCounter = 0;
      var formSetDirtyFn = form.$setDirty;
      form.$setDirty = function() {
        me.dirtyCounter++;
        formSetDirtyFn();
      };
    },
    controller: function() {
      this.$notifyPristine = function() {
        if (this.dirtyCounter === 0) return;
        if (this.dirtyCounter === 1) {
          this.dirtyCounter = 0;
          if (this.form) this.form.$setPristine();
        } else {
          this.dirtyCounter--;
        }
      };
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

然后,自定义输入指令需要require: ["ngModel", "^pristinableForm"]调用pristinableForm.$notifyPristine()其重置函数:

scope.reset = function(){
  if (ngModel.$dirty){
    scope.counter = original;
    ngModel.$setViewValue(scope.counter);
    ngModel.$setPristine();
    pristinableForm.$notifyPristine();
  }
};
Run Code Online (Sandbox Code Playgroud)

用法是:

<div ng-form="form" pristinable-form>
  <counter ng-model="count1"></counter>
  <counter ng-model="count2"></counter>
  <input ng-model="foo" name="anotherControl">
</div>
Run Code Online (Sandbox Code Playgroud)

笨蛋