隔离范围和“替换:真"的问题;在角度指令中 [英] Issue with isolated scope and "replace: true" in angular directive

查看:29
本文介绍了隔离范围和“替换:真"的问题;在角度指令中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用 AngularJS 制作错误消息指令时,我一直在努力解决范围问题.

我有一个 ng-if 和 ng-class 指令作为指令模板的一部分,但 ng-class 指令中的表达式似乎总是返回一个空字符串,除非:

  1. 我删除了 ng-if 指令.
  2. 或者,我删除了指令定义对象中的替换"键.

查看我的指令的编译输出,如果 ng-if 或 replace 键被删除,它看起来像是在创建一个隔离的范围,但如果它们都留在里面,那么就没有 ng-isolate-scopehtml 输出中的类,只是 ng-scope.

我真的很想确切地了解这里发生了什么,并感谢您的任何解释.

指令定义

angular.module('myMessages').directive('pageMes​​sages', function() {返回 {限制:'E',替换:真的,范围: {消息:'='},控制器:功能($范围){$scope.severity = '警报成功';},模板:'<div ng-if="messages.length > 0">'+'<div class="alert" ng-class="severity">'+'
    '+'<li ng-repeat="m in messages">{{::m.message}}</li>'+'</ul>'+'</div>'+'</div>'};});

输出(注意没有添加alert-danger类)

<!-- ngIf:messages.length >0 --><div ng-if="messages.length > 0" messages="messages" class="ng-scope"><div class="alert" ng-class="severity"><ul><!-- ngRepeat: m 在消息中--><li ng-repeat="m in messages" class="ng-binding ng-scope">测试错误</li><!-- end ngRepeat: m in messages --></ul>

<!-- end ngIf:messages.length >0 --></div>

alert-danger 类是在移除 replace 后添加的(移除 ng-if 也可以)

<!-- ngIf:messages.length >0 --><div ng-if="messages.length > 0" class="ng-scope"><div class="alert alert-danger" ng-class="severity"><ul><!-- ngRepeat: m 在消息中--><li ng-repeat="m in messages" class="ng-binding ng-scope">测试错误</li><!-- end ngRepeat: m in messages -->

<!-- end ngIf:messages.length >0 --></page-messages>

解决方案

truthy ng-if 的工作是克隆一个原始元素并赋予它继承的范围.它为此使用了嵌入,这允许 ng-if 在具有隔离作用域的元素上获得继承的作用域,避免 $compile:multidir 错误和 Multiple 指令请求新的/isolated scope 判断.

好消息是,如果在具有隔离作用域的元素上使用它,它不会抛出错误.坏处是当在具有更高优先级(ng-if 优先级为 600)的指令上使用时,它只会替换它,而忽略它的作用域.另一件坏事是,当在具有独立作用域的指令的根模板元素上使用时(如这个),它只会用从父作用域继承其作用域的克隆元素替换元素(属于指令的父元素,因为它自己的元素已被替换为 replace).

所以它只是从 pageMes​​sages 父作用域中获取 severity 值,如果 ng-class 表达式不存在,则将其计算为空字符串.

解决方案是不要在带有 replace 标志的指令的根元素上使用 ng-if.replace 标志 已被弃用,这意味着问题不会被修复.当指令的模板获得一个额外的 <div> 包装器时(尽管它可能违背 replace 的目的),一切都应该按预期工作.

I have been struggling with a scoping issue when making an error message directive using AngularJS.

I have an ng-if and ng-class directive as part of the directive template, but the expression in the ng-class directive always seemed to return a blank string, unless:

  1. I removed the ng-if directive.
  2. or, I removed the 'replace' key in the directive definition object.

Looking at the compiled output for my directive, it looks like an isolated scope is being created if the ng-if or the replace key is removed, but if they are both left in, then there are no ng-isolate-scope classes in the html output, just ng-scope.

I would really like to understand exactly what is going on here and would be grateful for any explanations.

Directive Definition

angular.module('myMessages')
.directive('pageMessages', function() {

    return {
        restrict: 'E',
        replace: true,
        scope: {
            messages: '='
        },
        controller: function($scope) {
            $scope.severity = 'alert-success';
        },
        template: '<div ng-if="messages.length > 0">' +
                    '<div class="alert" ng-class="severity">' + 
                        '<ul>' + 
                            '<li ng-repeat="m in messages">{{::m.message}}</li>' +
                        '</ul>' +
                    '</div>' +
                  '</div>'
    };
});

Output (note no alert-danger class is added)

<!-- ngIf: messages.length > 0 -->
<div ng-if="messages.length > 0" messages="messages" class="ng-scope">
    <div class="alert" ng-class="severity">
        <ul>
        <!-- ngRepeat: m in messages -->
            <li ng-repeat="m in messages" class="ng-binding ng-scope">test error</li>
        <!-- end ngRepeat: m in messages --></ul>
    </div>
</div>
<!-- end ngIf: messages.length > 0 --></div>

alert-danger class is added after removing replace (removing ng-if would work as well)

<page-messages messages="messages" class="ng-isolate-scope">
    <!-- ngIf: messages.length > 0 -->
    <div ng-if="messages.length > 0" class="ng-scope">
        <div class="alert alert-danger" ng-class="severity">
            <ul>
            <!-- ngRepeat: m in messages -->
                <li ng-repeat="m in messages" class="ng-binding ng-scope">test error</li>
            <!-- end ngRepeat: m in messages -->
            </ul>
        </div>
    </div>
    <!-- end ngIf: messages.length > 0 -->
</page-messages>

解决方案

The job of truthy ng-if comes to cloning an original element and giving it inherited scope. It uses transclusion for that, this allows ng-if to get inherited scope on an element with isolated scope, avoiding $compile:multidir error with Multiple directives requesting new/isolated scope verdict.

The good thing is that it won't throw an error if it is used on an element with isolated scope. The bad thing is when used on a directive with higher priority (ng-if priority is 600) it will just replace it, ignoring its scope. And another bad thing is that when used on on root template element of a directive with isolated scope (like this one) it will just replace an element with cloned one that inherits its scope from parent scope (belonging to directive's parent element, because its own element was already replaced with replace).

So it just gets severity value from pageMessages parent scope and evaluates ng-class expression to empty string if it doesn't exist.

The solution is to not use ng-if on root element of a directive with replace flag. replace flag has got deprecation status, which means that issues won't be fixed. When directive's template gets an extra <div> wrapper (though it may serve against the purpose of replace), everything should work as intended.

这篇关于隔离范围和“替换:真"的问题;在角度指令中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆