更新1:添加更多细节
更新2:添加了plunker代码以重现问题。请参阅以下链接
更新3:我在github上得到了角度团队的回复。检查here。
更新4:根据AngularJS团队的要求在github上发布更新。此外,我之前添加的建议解决方案证明它正在创建一个新的视觉问题。请参阅以下详细信息
更新5:从Angular团队获得另一个反馈。我认为我们80%接近找到解决方案。
我在我的项目中实现了Angular UI datepicker,过了一段时间,我注意到当我打开弹出框并点击月份更改为另一个月时,另一个弹出窗口显示在现有弹出窗口的顶部。请参阅下面的快照以获取更多详细信息:
最初,当我点击月份时,当前弹出窗口应该消失,另一个弹出窗口应显示以选择新月份。
然而,当我在月份点击两次(下面以黄色突出显示)时,弹出窗口将消失,并且它将正常工作。但是,在我选择一个日期之后,问题就会回来。
我使用的是与角度ui datepicker官方演示网站相同的示例代码。在下面找到相关网站和plunker代码:
http://angular-ui.github.io/bootstrap/versioned-docs/1.3.3/#/datepickerPopup http://plnkr.co/edit/lEgJ9eC9SzBWsgVhhQkq?p=preview
我的代码与上面的plunker示例中的代码完全相同。唯一的区别是我使用$compile
服务动态添加所需的字段验证。
经过大量的故障排除后,发现$compile()
服务导致了这种行为。我做了一些研究,发现$compile
服务还会在下拉列表或select
元素中导致重复的项目。我使用了提议的解决方法并且它有效。请参阅以下代码:
$compile(child)(elmScope, function (clone) {
angular.element(child).after(clone);
angular.element(child).remove();
});
我使用$compile
的原因是使用此方法here从DB向元素添加动态验证规则。
我收到reply from angular team on github后,发现他们suggested this fix:
.directive('checkIfRequired', ['$compile', function ($compile) {
return {
priority: 1000,
terminal: true,
/*require: '?ngModel',*/
//JIRA: NE-2535 - inject the current 'ngForm' controller with this directive
// This is required to add automatice error message when the Form Field is invalid.
require: '?^form',
link: function (scope, el, attrs, ngForm) {
el.removeAttr('check-if-required');
el.attr('ng-required', 'true');
$compile(el, 1000)(scope);
}
};
}]);
当我尝试应用建议的修复程序时,我收到大量错误。似乎在使用terminal=true
时,'ng-init'下的内部元素中的所有代码都没有被执行。我注意到许多范围变量变为“未定义”。
这是尝试找到解决方案的final update on github。请参阅以下代码:
app.directive('checkIfRequired', ['$compile', '$timeout', function ($compile, $timeout) {
return {
priority: 2000,
terminal: true,
/*link: function (scope, el, attrs) {
el.removeAttr('check-if-required');
var children = $(':input', el);
children.each(function(key, child) {
if (child && child.id === 'test_me') {
angular.element(child).attr('ng-required', 'true');
}
});
$compile(children)(scope);
},*/
compile: function (el, attrs) {
el.removeAttr('check-if-required');
var children = $(':input', el);
children.each(function(key, child) {
if (child && child.id === 'test_me') {
angular.element(child).attr('ng-required', 'true');
}
});
var compiled = $compile(children, null, 2000);
return function( scope ) {
compiled( scope );
};
}
};
}]);
感谢您在我的项目中以正确的方式应用修复程序的帮助。 See the related parts of the code here
之前我发布了一个解决方案,但之后我删除了它。我后来注意到它引起了一种有趣的堆叠效应,这比我之前报道的更糟糕。
以下是github上的更新,其中包含完整的详细信息:
https://github.com/angular/angular.js/issues/15956#issuecomment-300324812
当我收到AngularJS团队的回复时,会不断更新。
在我找到永久性解决方案之前,请耐心等待。
为避免此问题,请勿使用$compile
服务,或者必须使用此代码示例来解决问题:
$compile(child)(elmScope, function (clone) {
angular.element(child).after(clone);
angular.element(child).remove();
});
希望这对面临同样问题的其他人有价值。
答案 0 :(得分:0)
这是为了进行修正。之前添加的解决方案没有按预期工作。
有关完整的详细信息,请查看github上的更新:
https://github.com/angular/angular.js/issues/15956#issuecomment-300324812
现在我可以提出一种不同的方法来使用动态验证规则,这些规则存储在DB上并加载AngularJS表单。
请参考此处的代码部分作为此建议解决方案的基础:
Angular dynamic required validation of group of fields with field highlight if invalid
而不是在指令$compile
中使用check-if-required
,而是为字段scope
创建一个新的child.id
变量:
if (scope.isFieldRequired(child.id)) {
//angular.element(child).attr('ng-required', "true");
//$compile(child)(elmScope);
scope.RootController.ngRequired[child.id] = true;
} else {
scope.RootController.ngRequired[child.id] = false;
}
定义元素时,请确保它与以下内容类似:
<input id="customer_id" name="customer_id" ng-model="customer_id" ng-required="RootController.ngRequired.customer_id"/>
基本上,所有验证规则必须链接到范围变量,该变量必须在根角度控制器RootController'. For simplicity, the required validation will be under
RootController.ngRequired`中定义。
有必要在最顶层的外部控制器上使用RootController
表示法定义controller as
。否则,上述解决方案将无法正常工作。以下是根控制器的示例元素定义:
<body ng-app="myApp" ng-controller="formMainController as RootController">
...
</body>
如果我没有得到Angular团队关于因使用$compile
而发现的问题的满意答复,我将转而采用上述方法。我几乎可以肯定上述方法可行。
如果您有任何反馈意见,请执行此操作。
塔雷克
答案 1 :(得分:0)
这是我从github的AngularJS团队获得的另一个解决方案。 Click here to see the answer at github
请参考此处的代码部分作为此建议解决方案的基础:
Angular dynamic required validation of group of fields with field highlight if invalid
基本上,您可以使用以下代码示例来避免在指令链接函数中使用$compile
时出现双重编译问题:
app.directive('checkIfRequired', ['$compile', '$timeout', function ($compile, $timeout) {
return {
priority: 2000,
terminal: true,
link: function (scope, el, attrs) {
el.removeAttr('check-if-required');
$(':input', el).each(function(key, child) {
if (child && child.id === 'test_me') {
angular.element(child).attr('ng-required', 'true');
}
});
$compile(el, null, 2000)(scope);
}
};
}]);
这是必需的,你有一个循环遍历与指令check-if-required
相关的父元素。