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 绝对是一个很棒的框架,但不幸的是,在我看来,一些基本过程不够明确。