4

您可以在此 jsFiddle 中对其进行测试:HERE (最好在新的 jsFiddle 上查看,请参阅本文的编辑部分)

我认为 AngularJS 中存在错误,或者至少不是预期的结果。如果我分离一个表单然后重新附加它,它的类ng-invalid切换到ng-valid重新附加到 DOM。即使数据无效,这也会导致启用表单的提交按钮。当然,我期待有效性状态不会切换。

我认为这是一个角度错误,但可能是一个 jquery 错误。我可以使用 jquery 检查附加表单是否有效,然后强制表单类,但它似乎不能作为有效表单工作,然后获取无效状态。这很奇怪,因为在分离之前不使用某种数据来保存状态表单,我不知道任何其他解决方法。

那么有人已经遇到过这个问题吗?有什么方法(如果可能的话使用 AngularJS 指令)来摆脱这个错误?

PS:我需要在单页 Web 应用程序中分离表单(和任何其他元素)以保持 DOM 尽可能干净。

编辑

我已经完成了一个新的 jsFiddle,它更多地说明了我的问题,在内部站点导航上分离内容:http: //jsfiddle.net/EWVwa/

更新

我来到这个临时解决方案(感谢CaioToOn)

http://plnkr.co/edit/KIgMz2

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
});


app.directive('customValidation', function() {
  return {
    require: ['ngModel', '^?form'],
    link: function(scope, element, attr, ctrls) {
      console.log(ctrls);
      var ngModelCtrl = ctrls[0],
          formCtrl = ctrls[1];


      ngModelCtrl.$parsers.push(function(viewValue) {
        if (viewValue === 'test') {
          ngModelCtrl.$setValidity('name', true);
          formCtrl.$setValidity('name', true);
          return viewValue;
        } else {
          ngModelCtrl.$setValidity('name', false);
          formCtrl.$setValidity('name', false);
          return undefined;
        }
      });


      // custom event
      element.bind('$append', function() {
        formCtrl && formCtrl.$addControl(ngModelCtrl);
        /*** TEST for to keep form's validation status ***/
        formCtrl.$setValidity('name', ngModelCtrl.$valid);
        //ngModelCtrl.$setValidity('name', ngModelCtrl.$valid);
        console.log(formCtrl.$valid);
      });
      //binding on element, not scope. 
      element.bind('$destroy', function() {
        console.log("gone haven");        
      });
    }
  };
});

这需要更多关于多输入验证的测试。完成所有测试后,我肯定会更新答案。

4

1 回答 1

3

出现问题是因为当从 DOM 中删除元素时,input指令会从表单控件中删除自己。由于它不再链接您ngModel和表单控制器,因此表单不再考虑您的输入。

你基本上有两个三个选项:

  • 更改元素可见性而不是删除它
  • (更喜欢下面的那个)公开一个“重新链接”功能,将其重新添加到原始表单中
  • 在所有控件上触发自定义事件,以便它们可以重新链接自己

更改元素可见性意味着您将在 DOMTree 中拥有不必要的 DOM 元素。这还不错,因为您仍然保留对 $compile 元素的引用,因此它将参与$digest循环和“DOM”修改。

想了一会儿,新的解决方案比这个稍微好一点,所以不要暴露relink函数)暴露relink函数是很奇怪的(虽然是功能性的),这不是最可靠的解决方案。实现它的一种方法是要求表单控制器(require: ['ngModel', '^?form'])并将重新链接函数绑定到元素的数据:

element.data('relink', function(){
  formCtrl && formCtrl.$addControl(ngModelCtrl);
});

当您再次将元素添加到屏幕时,您将不得不调用所有控件的重新链接函数:

$('.controls').data('relink')();

请参阅此处的示例。

它不太可靠,但可能适用于您的情况。

触发自定义事件与之前的几乎相同,但您将在所有应该重新链接自身的元素上调度自定义事件。这样更有条理,但仍然不太可靠,因为表单和其他链接也可能已损坏(再次,应该足以满足您的情况)。基本上听你的指令的自定义事件:

element.bind('$append', function(){
  formCtrl && formCtrl.$addControl(ngModelCtrl);
});

并且更改为表单后,只需在所有控件上触发自定义事件即可:

$('.control').triggerHandler('$append');

这个更好的原因是指令仍然决定何时重新链接组件,并且事件是一种“通用”。这是一个工作的plunker

作为最后的努力,您可以jQuery.fn.append递归地覆盖并触发所有子元素上的自定义事件(这是Angular在删除元素时所做的)。这是最有条理的,但它会影响您在所有append呼叫中的表现。

于 2013-04-20T18:15:42.317 回答