Javascript 分离然后附加AngularJS表单更改有效状态
您可以在这个jsFiddle中测试它:(最好是在新的jsFiddle上查看,请参阅本文的编辑部分) 我认为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类,但它似乎不能
ng invalid
将切换到ng valid
,然后将其重新附加到DOM。即使数据无效,也会导致启用表单的提交按钮。
当然,我希望有效性状态不会切换
我认为这是一个角度错误,但可能是一个jquery错误。
我可以使用jquery检查append上的表单是否有效,然后强制执行form类,但它似乎不能作为有效表单工作,然后获取invalid的状态。这是非常奇怪的,因为我不知道任何其他的解决办法,如果不在分离之前使用某种数据来保存状态表单
那么有人已经遇到过这个问题了?
是否有任何方法(如果可能的话,使用AngularJS指令)来消除这个bug
PS:我需要在一个单页web应用程序中分离表单(和任何其他元素),以保持DOM尽可能干净
编辑
我做了一个新的JSFIDLE,它进一步说明了我的问题,分离了内部站点导航上的内容:
更新
我找到了这个临时解决方案(感谢Caioton)
这需要更多关于多输入验证的测试。当所有测试都完成时,我肯定会更新答案。问题发生的原因是,当元素从DOM中删除时,表单控件中的
输入
指令本身。由于它不再链接您的ngModel
和表单控制器,表单不再考虑您的输入
您基本上有两个或三个选项:
- 更改图元可见性,而不是将其删除
- (首选下面的一个)公开一个“重新链接”函数,将其重新添加到原始表单中
- 在所有控件上触发自定义事件,以便它们可以重新链接自己
$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");
});
}
};
});