2

ctrl.$setValidity在我的一个指令中使用使表单无效。但是,有一种方法存在于其他地方,可以在不同的条件下从 DOM 中删除该元素。当我使表单无效$setValidity然后删除有问题的元素时会发生什么是表单仍然无效,而我希望它做的是根据其新的 Inputfield 集重新计算其有效性。

请注意,我不只是在寻找ctrl.$setValidity true, (表单中的其他输入字段可能有效也可能无效),我只是希望表单重新计算。

以下是指令代码:

 app.directive('dir', function() {
   return {
      restrict: 'C',
      require: "ngModel",
      link: function(scope, element, attrs, ctrl) {
      someValue = scope.someValue;
      someField = element.find(".some-class");

      monitorField = function(newValue, oldValue){
        console.log("whee");
        scope.someFunction(newValue);
        if(newValue =="Invalidate NOW!"){
        ctrl.$setValidity('someClass', false);      
        } else if (oldValue == "Invalidate NOW!"){
           angular.element(document.querySelector('.some-class')).remove();
        } else {
          ctrl.$setValidity('someClass', true); 
       }
    }  
    scope.$watch("someValue", monitorField, true);
   }
 }
});

运行于:

   <FORM class="dir" ng-model="someValue">
     <INPUT type="text" class="some-class" ng-model="someValue"/>
     <INPUT type="text" class="some-other-class"/>
   </FORM>

(是的,这是一个有点做作的例子)。

问题在这里重现:http: //jsfiddle.net/kTuAY/

在我的实际代码中,我根据对象数组填充输入字段,这些对象通过 Service 填充,并通过 array.splice 删除元素。jsfiddle 中给出的示例只是为了简单起见。

在这个小提琴中可以看到另一个有趣的失败情况:

http://jsfiddle.net/JACAv/

具体来说,如果其中一个输入依赖于值与另一个不冲突,因此无效,那么在更改其他字段值之后,有效性仍然不正确。

我上班时暂时不能正常工作的小提琴:

http://jsfiddle.net/yQpHL/

谢谢!

4

3 回答 3

2

如果可能,应该通过删除模型指向的 $scoped 对象的一部分来删除链接到模型的一部分的 DOM 元素。想想基本的 ngRepeat,如果你从数组中删除一个项目,它就会从 DOM 中删除一个元素。您的表单应该以相同的方式工作。这将防止这种情况发生。所有验证信息都包含在 $scope 中的模型中......就像这样: $scope.myForm.model.$error.required例如。如果您删除模型指向的 $scope 属性或数组项(例如$scope.foo$scope.items.splice(2,1),Angular 将知道(大概在下一个 $digest 期间)删除模型以及它的验证信息。

删除控制器或指令中的项目无关紧要,但应该从 $scope 中删除它,然后需要进行摘要以更新 UI 和验证。

我希望这会有所帮助,因为我觉得我偶然发现了我想说的话......

于 2013-01-18T22:27:59.190 回答
0

我不认为问题出在指令中,而是在“其他”代码中

如果 DOM 元素删除是在响应“本机”事件时完成的 - 即拖放事件、ajax 事件或其他事件,则角度框架将不知道自己运行重新计算。在此代码中,完成更新后,您必须在适当的范围内调用 $scope.$apply()。

哦,我看到了你的小提琴......好的。让生活变得更轻松一些怎么样 - 为什么不使用 ng-show 属性来装饰它,而不是删除你的 DOM 元素,让 Angular 来处理其余的事情呢?

于 2013-01-18T22:09:00.237 回答
0

我最终解决这个问题的方法是:

  1. 在结束的数组上放置一个单独的监视表达式ng-repeated
  2. 在该监视表达式中,构造当前存在于与相关指令匹配的输入字段中的所有值的哈希。
  3. 用 强制重置这些字段的值.val(),然后调用$compile内部字段以重新触发内部监视表达式
  4. 在函数中添加控制器上的输入字段值(之前ctrl.$setValidity从内部指令调用的函数:
    • 验证输入值的次数是否为 1
    • 重置被 ng 重复的数组以包含哈希值

好的:

  • 当删除一个元素时,外部监视(整个数组上的监视)触发,重新计算哈希,重置每个字段的值并重新验证
  • 当检测到碰撞时,它会正确冒泡,将所有碰撞字段标记为无效,当碰撞被移除时,所有字段都重新验证
坏处:
  • 每次数组更改时对每个字段调用 $compile 计算效率低下
  • 由于内部 watch 表达式会在值更改时触发一次,而外部 watch 表达式调用 compile 时会触发一次,因此有效的$digest's 的数量增加了一倍

清理代码后,我将整理一个代码示例。

于 2013-01-25T09:38:52.567 回答