你可以在这个jsFiddle中测试它:HERE(更好的是看新的jsFiddle,参见 EDIT 这篇文章的一部分)
我认为AngularJS中存在一个错误,或者至少没有预期的结果。
如果我分离表单然后重新附加它,它的类ng-invalid
切换到ng-valid
重新附加到DOM。因此,即使数据无效,也可以启用表单的提交按钮。
当然,我期待有效状态不会改变。
我认为这是一个有角度的错误,但也许是一个jquery错误。 如果表单有效,我可以使用jquery检查append,然后强制表单类,但它似乎不能作为有效表单获取然后无效状态。这很奇怪,因为我不知道任何其他解决方法而不使用各种数据来保存状态表单,然后再将其分离。
所以任何人都已经遇到过这个问题? 是否有任何方法(如果可能使用AngularJS指令)来摆脱这个错误?
PS:我需要在单页面Web应用程序中分离表单(和任何其他元素),以保持DOM尽可能干净。
修改
我做了一个新的jsFiddle,它解释了我的更多问题,在内部网站导航上分离内容:http://jsfiddle.net/EWVwa/
更新
我来到这个临时解决方案(感谢CaioToOn)
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");
});
}
};
});
这需要更多关于多输入验证的测试。当所有测试都完成时,我肯定会更新答案。
答案 0 :(得分:3)
问题发生是因为表单中的input
指令removes本身控制从DOM中删除元素的时间。由于它不会再次链接您的ngModel
和表单控制器,因此表单不再考虑您的输入。
你基本上有两个三个选项:
更改元素可见性意味着您将在DOMTree中拥有不必要的DOM元素。这并不是很糟糕,因为你总是保留对$ compile元素的引用,所以它还会参与$digest
周期和“DOM”修改。
(经过一段时间的考虑,新解决方案略好于此,所以不要公开重新链接功能) 公开重新链接功能 非常奇怪(虽然功能齐全),但这不是最可靠的解决方案。实现它的一种方法是要求表单控制器(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
次来电的性能。