angular-messages 嵌套指令,如何让它与其他指令一起工作
angular-messages nested directive, how to keep it working with other directives
我正在玩 AngularJS 以发现它的强大功能,但我不得不承认文档不是很发达,所以我在这里向社区询问我在嵌套指令方面遇到的问题。
我更多的是寻找原因(以及对我做错了什么的解释)而不是最终的解决方案。
事情是这样的(我正在使用 angular-messages 但我认为这并不重要,因为这个问题对于任何指令都是常见的):
为了快速更改错误管理,我决定将管理器(angular-此处的消息)封装到一个指令中,以便在表单上显示我的错误,我这样做了:
<script type="text/ng-template" id="default-error-messages">
<error-message data-error="email" data-message="This field is not a valid email"></error-message>
<error-message data-error="required" data-message="This field is required"></error-message>
<error-message data-error="minlength" data-message="This field is too short"></error-message>
</script>
<form data-ng-submit="submitForm(registrationForm)" method="POST" name="registrationForm" novalidate>
<input type="email" name="email" data-ng-model="user.email" required>
<error-container data-watch-error-on="registrationForm.email.$error" data-default-errors="default-error-messages" data-ng-if="registrationForm.email.$dirty">
<error-message data-error="required" data-message="test"></error-message>
</error-container>
<button type="submit" data-ng-disabled="registrationForm.$invalid">Register</button>
</form>
directives.directive('errorContainer', ['$compile',function($compile){
return{
restrict: 'E',
transclude: true,
replace: false,
scope: {
watchErrorOn: '@'
},
template: '<div class="error-container" data-ng-transclude></div>',
compile: function(tElt, tAttrs, ctrl) {
return {
pre: function(scope, iElement, iAttrs){
iElement.find('.error-container').attr("data-ng-messages", scope.watchErrorOn);
},
post: function(scope, iElement, iAttrs){
if (angular.isDefined(iAttrs.defaultErrors)) {
var errorList = angular.element("<div data-ng-messages-include='" + (iAttrs.defaultErrors || 'default-error-messages') + "'></div>");
iElement.find('.error-container').append(errorList);
$compile(iElement)(scope);
}
}
}
},
link: function(scope, element, attrs, ctrl){
$compile(element)(scope);
}
}
}]);
directives.directive('errorMessage', ['$compile', function($compile){
return{
restrict: 'E',
template: '<div class="error"></div>',
replace: true,
scope:{
message:'@',
error:'@'
},
compile: function(tElt, tAttrs, ctrl){
return{
pre: function(scope, iElement, iAttrs){
iElement.attr('data-ng-message', scope.error);
iElement.text(scope.message);
}
}
}
}
}]);
如您所知,它不起作用,模板中根本不包含默认错误。
我在 pre/post 编译函数和 link 上尝试了很多组合,但没有成功。
我认为这是编译优先级的问题,也许 ng-messages-include 应该是最后一个编译但不知道如何编译,提前谢谢
您应该在指令独立作用域中使用 =
而不是 @
,这会将 data-watch-error-on="registrationForm.email.$error"
值直接传递给独立作用域 watchErrorOn
变量。
scope: {
watchErrorOn: '='
},
当你使用 @
时,它表示一种绑定方式并且需要在 {{}}
插值指令中传递值,但重要的是你想传递 true
& false
值到指令 isolated scope
,但在将插值中的值传递给指令后,会将 bool
值转换为字符串,如 "false"
& "true"
如果在我们的指令中检查,则不需要。使用 =
传递值只不过是两种方式的绑定,当您从指令元素传递它时,它将使您的值保持为 boolean
。
好吧,我在 GitHub 上被 post 引导后找到了解决方案。
正如所怀疑的那样,问题是由 AngularJS 的编译策略引起的。
所以简而言之,关键是将 include 所有指令直接放在模板上,包括它们之后仍然可以工作,但需要手动编译元素。
完全奇怪的是,预编译功能自然会与编译阶段之前的"modifying the template string"相同,但显然并非如此。
所以请考虑以下有效的解决方案:
html :
<form method="POST" name="registrationForm" novalidate>
<input type="email" name="email" placeholder="Email address" data-ng-model="user.email" autocomplete="off" required>
<button type="submit">Register</button>
<error-container data-messages-include="my-custom-messages" data-error-watch="registrationForm.email.$error">
<error-message data-error="required" data-message="This field is required (version 1)"></error-message>
<error-message data-error="email" data-message="This field must be an email"></error-message>
</error-container>
</form>
指令:
var app = angular.module('app', ['ngMessages']);
app.directive('errorContainer', function(){
return{
template: '<div ng-messages="watch"><div ng-messages-include="{{ messagesInclude }}"></div><div ng-transclude></div></div>',
scope: {
watch: '=errorWatch',
messagesInclude: '@messagesInclude'
},
transclude: true
};
});
app.directive('errorMessage', [function(){
return{
scope: {
error: '@error',
message: '@message'
},
template: '<div ng-message="{{ error }}">{{ message }}</div>',
replace: true
}
}]);
最后一句话,AngularJS 绝对是一个很棒的框架,但不幸的是,在我看来,一些基本过程不够明确。
我正在玩 AngularJS 以发现它的强大功能,但我不得不承认文档不是很发达,所以我在这里向社区询问我在嵌套指令方面遇到的问题。
我更多的是寻找原因(以及对我做错了什么的解释)而不是最终的解决方案。
事情是这样的(我正在使用 angular-messages 但我认为这并不重要,因为这个问题对于任何指令都是常见的):
为了快速更改错误管理,我决定将管理器(angular-此处的消息)封装到一个指令中,以便在表单上显示我的错误,我这样做了:
<script type="text/ng-template" id="default-error-messages">
<error-message data-error="email" data-message="This field is not a valid email"></error-message>
<error-message data-error="required" data-message="This field is required"></error-message>
<error-message data-error="minlength" data-message="This field is too short"></error-message>
</script>
<form data-ng-submit="submitForm(registrationForm)" method="POST" name="registrationForm" novalidate>
<input type="email" name="email" data-ng-model="user.email" required>
<error-container data-watch-error-on="registrationForm.email.$error" data-default-errors="default-error-messages" data-ng-if="registrationForm.email.$dirty">
<error-message data-error="required" data-message="test"></error-message>
</error-container>
<button type="submit" data-ng-disabled="registrationForm.$invalid">Register</button>
</form>
directives.directive('errorContainer', ['$compile',function($compile){
return{
restrict: 'E',
transclude: true,
replace: false,
scope: {
watchErrorOn: '@'
},
template: '<div class="error-container" data-ng-transclude></div>',
compile: function(tElt, tAttrs, ctrl) {
return {
pre: function(scope, iElement, iAttrs){
iElement.find('.error-container').attr("data-ng-messages", scope.watchErrorOn);
},
post: function(scope, iElement, iAttrs){
if (angular.isDefined(iAttrs.defaultErrors)) {
var errorList = angular.element("<div data-ng-messages-include='" + (iAttrs.defaultErrors || 'default-error-messages') + "'></div>");
iElement.find('.error-container').append(errorList);
$compile(iElement)(scope);
}
}
}
},
link: function(scope, element, attrs, ctrl){
$compile(element)(scope);
}
}
}]);
directives.directive('errorMessage', ['$compile', function($compile){
return{
restrict: 'E',
template: '<div class="error"></div>',
replace: true,
scope:{
message:'@',
error:'@'
},
compile: function(tElt, tAttrs, ctrl){
return{
pre: function(scope, iElement, iAttrs){
iElement.attr('data-ng-message', scope.error);
iElement.text(scope.message);
}
}
}
}
}]);
如您所知,它不起作用,模板中根本不包含默认错误。 我在 pre/post 编译函数和 link 上尝试了很多组合,但没有成功。 我认为这是编译优先级的问题,也许 ng-messages-include 应该是最后一个编译但不知道如何编译,提前谢谢
您应该在指令独立作用域中使用 =
而不是 @
,这会将 data-watch-error-on="registrationForm.email.$error"
值直接传递给独立作用域 watchErrorOn
变量。
scope: {
watchErrorOn: '='
},
当你使用 @
时,它表示一种绑定方式并且需要在 {{}}
插值指令中传递值,但重要的是你想传递 true
& false
值到指令 isolated scope
,但在将插值中的值传递给指令后,会将 bool
值转换为字符串,如 "false"
& "true"
如果在我们的指令中检查,则不需要。使用 =
传递值只不过是两种方式的绑定,当您从指令元素传递它时,它将使您的值保持为 boolean
。
好吧,我在 GitHub 上被 post 引导后找到了解决方案。
正如所怀疑的那样,问题是由 AngularJS 的编译策略引起的。 所以简而言之,关键是将 include 所有指令直接放在模板上,包括它们之后仍然可以工作,但需要手动编译元素。
完全奇怪的是,预编译功能自然会与编译阶段之前的"modifying the template string"相同,但显然并非如此。
所以请考虑以下有效的解决方案:
html :
<form method="POST" name="registrationForm" novalidate>
<input type="email" name="email" placeholder="Email address" data-ng-model="user.email" autocomplete="off" required>
<button type="submit">Register</button>
<error-container data-messages-include="my-custom-messages" data-error-watch="registrationForm.email.$error">
<error-message data-error="required" data-message="This field is required (version 1)"></error-message>
<error-message data-error="email" data-message="This field must be an email"></error-message>
</error-container>
</form>
指令:
var app = angular.module('app', ['ngMessages']);
app.directive('errorContainer', function(){
return{
template: '<div ng-messages="watch"><div ng-messages-include="{{ messagesInclude }}"></div><div ng-transclude></div></div>',
scope: {
watch: '=errorWatch',
messagesInclude: '@messagesInclude'
},
transclude: true
};
});
app.directive('errorMessage', [function(){
return{
scope: {
error: '@error',
message: '@message'
},
template: '<div ng-message="{{ error }}">{{ message }}</div>',
replace: true
}
}]);
最后一句话,AngularJS 绝对是一个很棒的框架,但不幸的是,在我看来,一些基本过程不够明确。