Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 分离然后附加AngularJS表单更改有效状态_Javascript_Jquery_Angularjs_Angularjs Directive - Fatal编程技术网

Javascript 分离然后附加AngularJS表单更改有效状态

Javascript 分离然后附加AngularJS表单更改有效状态,javascript,jquery,angularjs,angularjs-directive,Javascript,Jquery,Angularjs,Angularjs Directive,您可以在这个jsFiddle中测试它:(最好是在新的jsFiddle上查看,请参阅本文的编辑部分) 我认为AngularJS中存在缺陷,或者至少不是预期的结果。 如果我分离一个表单,然后重新附加它,它的类ng invalid将切换到ng valid,然后将其重新附加到DOM。即使数据无效,也会导致启用表单的提交按钮。 当然,我希望有效性状态不会切换 我认为这是一个角度错误,但可能是一个jquery错误。 我可以使用jquery检查append上的表单是否有效,然后强制执行form类,但它似乎不能

您可以在这个jsFiddle中测试它:(最好是在新的jsFiddle上查看,请参阅本文的编辑部分)

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

我认为这是一个角度错误,但可能是一个jquery错误。 我可以使用jquery检查append上的表单是否有效,然后强制执行form类,但它似乎不能作为有效表单工作,然后获取invalid的状态。这是非常奇怪的,因为我不知道任何其他的解决办法,如果不在分离之前使用某种数据来保存状态表单

那么有人已经遇到过这个问题了? 是否有任何方法(如果可能的话,使用AngularJS指令)来消除这个bug

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

编辑

我做了一个新的JSFIDLE,它进一步说明了我的问题,分离了内部站点导航上的内容:

更新

我找到了这个临时解决方案(感谢Caioton)


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

问题发生的原因是,当元素从DOM中删除时,表单控件中的
输入
指令本身。由于它不再链接您的
ngModel
和表单控制器,表单不再考虑您的输入

您基本上有两个或三个选项:

  • 更改图元可见性,而不是将其删除
  • (首选下面的一个)公开一个“重新链接”函数,将其重新添加到原始表单中
  • 在所有控件上触发自定义事件,以便它们可以重新链接自己
更改元素可见性意味着您将在DOMTree中拥有不必要的DOM元素。这并不是很糟糕,因为您始终保留对$compile元素的引用,因此它仍将参与
$digest
循环和“DOM”修改

(经过一段时间的思考,新的解决方案略优于此解决方案,因此不要公开重新链接功能)公开重新链接功能非常奇怪(尽管功能正常),这并不是最可靠的解决方案。实现它的一种方法是要求表单控制器(
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');
这个更好的原因是指令仍然决定何时重新链接组件,并且事件有点“泛型”


作为最后一项工作,您可以重写
jQuery.fn.append
,并递归地触发所有元素子元素上的自定义事件(这就是删除元素时的情况)。这是最有条理的,但它会影响您在所有
append
调用中的性能。

感谢您发表这篇有趣的文章。我明天试试,然后告诉你。“公开一个重新链接函数”方法似乎正是我想要的。为了更好的解决方案(在添加的元素上触发自定义事件),我更改了“公开重新链接函数”。将仍然具有与前一个相同的限制和优点,但要好得多。使用您的Plunker,我能够得到我想要的东西:在分离/附加后,表单现在将按预期响应。我需要对表单中的多个验证输入进行更多测试(formCtrl.$setValidity('name',ngModelCtrl.$valid);在这种情况下不应准确)。顺便说一句,我不明白为什么“Errors”obj的“required”键在我的Plunker中仍然设置为false。我应该使用表单。我想是$error obj。就是说,非常感谢!
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");        
      });
    }
  };
});