【问题标题】:Detach then append AngularJS form change validity status分离然后附加 AngularJS 表单更改有效性状态
【发布时间】:2013-04-18 09:57:18
【问题描述】:

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

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

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

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

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");        
      });
    }
  };
});

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

【问题讨论】:

    标签: javascript jquery angularjs angularjs-directive


    【解决方案1】:

    出现问题是因为input 指令removes 本身来自表单控制何时从DOM 中删除元素。由于它没有再次链接您的ngModel 和表单控制器,因此表单不再考虑您的输入。

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

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

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

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

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

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

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

    查看示例here

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

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

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

    而改成表单后,只需在所有控件上触发自定义事件即可:

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

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

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

    【讨论】:

    • 感谢这篇有趣的帖子。我明天试试,然后告诉你。 “公开重新链接功能”方法似乎正是我正在寻找的。​​span>
    • 不错。我已经更改了“公开重新链接功能”以获得更好的解决方案(在添加的元素上触发自定义事件)。仍将具有与以前相同的限制和好处,但要好得多。
    • 使用你的 Plunker,我能够得到我想要的东西:plnkr.co/edit/KIgMz2 分离/附加后表单现在按预期响应。我需要对表单中的多个验证输入进行更多测试(formCtrl.$setValidity('name', ngModelCtrl.$valid); 在这种情况下不应该是准确的)。顺便说一句,我不明白为什么在我的 Plunker 中,'Errors' obj 的 'required' 键仍然设置为 false。我认为我应该使用 form.$error obj。说了这么多,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2014-05-06
    • 2015-05-13
    • 2022-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多