【问题标题】:Difference in scope between directive with template and without template AND between Angular 1.2 and 1.1?Angular 1.2 和 1.1 之间带模板和不带模板的指令之间的范围差异?
【发布时间】:2014-01-22 21:22:02
【问题描述】:

我是 Angular 的新手并试图了解高级指令 API - 我想使用指令元素属性在编译函数中重新创建指令模板。 但是当我没有模板集(或模板是空字符串)而不是访问隔离指令范围时,我访问父(控制器)范围。另外 - 这适用于 Angular 1.1 但不适用于 1.2

这里是 HTML:

<div class="container" ng-app="app" ng-controller="AppController">
      <sandbox title="Attribute Title"></sandbox>
</div>

JavaScript:

var app = angular.module('app', [], function () {});

app.controller('AppController', function ($scope) {
    $scope.title = "AppController title";
});

app.directive('sandbox', function ($log, $compile) {
    return {
        restrict: 'E',
        scope: {
            title: "@"
        },
        controller: function ($scope, $element, $attrs) {
            $scope.title = "Directive Controller title";
        },
        template: '<h1>Template</h1>', // change it to: '' and Run, than change Angular to 1.2.x
        compile: function (tElement, tAttrs) {
            tElement.append('<h2> Title = {{ title }}</h2>');
        }
    }

});

当你运行它时,你会得到:

模板

Title = 属性标题

但是当您将模板更改为空字符串时,您会使用 Angular 1.2:

Title = AppController 标题

使用 Angular 1.1.1:

Title = 属性标题

我的问题:

为什么设置模板和未设置模板时访问范围会有所不同?

为什么 Angular 1.1 和 1.2 之间存在差异(错误?- 没有“模板”的指令和带有孤立作用域的指令访问控制器作用域而不是指令作用域)?

如何在编译函数中构建访问 Angular 1.2 中的隔离范围而不是父范围的模板?

为什么指令控制器函数不使用 $scope.title = "..." 更改 'title' - 但是在调试 'link' 函数中的 'scope' 参数时,'title' 值是 'Directive Controler Title'但它在内部(在哪里寻找它)绑定了孤立的范围“属性值”?

这里是 JSFiddle 玩:http://jsfiddle.net/yoorek/zQ66L/4/

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    您发现了 1.2 中发生的重大变化(以及使用“@”的一个怪癖)。

    1) 当你的模板是 `` Angular 看不到要应用隔离范围的模板。这是 1.2 中的问题的原因在于您的第二个问题的答案。

    2) 这是 1.2 重大变化的结果-make isolate scope truly isolate

    隔离范围现在仅可用于请求它的隔离指令及其模板。

    因此,如果没有模板,您将附加到隔离范围之外的元素。
    来自https://github.com/angular/angular.js/issues/4889

    由于我们无法区分最初在 html 文件中的标记 以及在编译函数中添加的标记,后者也 没有得到隔离范围。

    ...编译函数中的附加标记应替换为使用 模板属性。
    这个想法是模板属性也可以是一个函数。如果它 是一,它将获得编译元素和编译属性为 参数。

    3) 正如您在上面看到的,Angular(1.2 后)确实是在试图推动您使用模板而不是此处的编译功能。您最好的选择可能是以您使用 compile 的方式使用模板函数。或者,您可以使用带有 $compile- 的链接函数,但这可能会增加不必要的复杂性。

    通过在 compile 函数中附加,您实际上只是在添加到模板中,因此它可以解决这个问题。

    4) 这与@ 的工作方式有关。来自Angulars guide to scopes

    在链接中使用 attrs.$observe('attr_name', function(value) { ... } 获取隔离范围属性的插值的函数 使用“@”符号。例如,如果我们在链接中有这个 函数 -- attrs.$observe('interpolated', function(value) { ... } -- 值将设置为 11。(scope.interpolatedProp 在 链接功能。相比之下,scope.twowayBindingProp 定义在 链接函数,因为它使用 '=' 符号。)

    你也可以读到这个SO post on the difference between @ and =

    【讨论】:

    • 很好的答案,但#4 已经有一段时间了。我认为从 1.1.x 开始,“@”将在链接函数的范围内定义。请参阅此示例:plnkr.co/edit/IVfc7P1a9Kj4RQTrp7Dx?p=preview
    • @dtabuenc 查看更新后的 plnkr:plnkr.co/edit/fH452EsTPjEJNJV0L6Xa 所以我相信使用范围版本(取决于继承)仍然存在风险——但我很乐意出错。
    • 链接函数中的$scope使用没问题,是控制器中的使用不正确。 “@”绑定是单向的,因此永远不应该被写入。写入其中的任何值都将在下一个摘要周期被覆盖。
    • @dtabuenc 请注意,Angular 使用从控制器in their transclude example 写入“@”绑定变量。所以我不确定我会称之为不正确 - 但肯定有风险,因此他们推荐$observe
    • @KayakDave 在 ng-transclude 中,他们正在写入 指令外部控制器中的 $scope.title ,这是完全合法的,因为它正在写入非隔离范围。这是自然的并且工作正常。问题是写入 $scope.title INSIDE 与隔离范围的指令。 “@”绑定变量不应该从指令的控制器或链接函数写入。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多