【问题标题】:How does one preserve scope with nested directives?如何使用嵌套指令保留范围?
【发布时间】:2014-02-24 15:55:03
【问题描述】:

我的目标是为可重用的轻量级 UI 元素创建一组灵活的指令。每个都有一个孤立的范围,其中许多都包含内容。我希望每个指令都是一个黑盒子——理想情况下,用户在编写要嵌入的内容时不需要知道它是否在内部嵌套了另一个指令。

根据Angular guide to directives

transclude 选项改变了范围嵌套的方式。它使得嵌入指令的内容具有指令外部的任何范围,而不是内部的任何范围。这样做时,它使内容可以访问外部范围。

我发现这在使用单个指令时可以正常工作。但是,如果有另一个指令嵌套在该指令中,该指令也包含内容,则被包含的内容将在外部指令的范围内解析,而不是在外部指令的范围内。这是一个问题,因为它使用户无法知道他们的嵌入内容将在什么范围内得到解决!

例如:(fiddle)

.controller('main', function ($scope) {
    $scope.value = '"main"';
    $scope.expected = $scope.value;
})

.directive('outer', function () {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        scope: { expected:'=' },
        controller: function ($scope) {
            $scope.value = '"outer"';
        },
        template: '<div><inner expected="expected"><span ng-transclude></span></inner></div>'
    };
})

.directive('inner', function () {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        scope: { expected:'=' },
        controller: function ($scope) {
            $scope.value = '"inner"';
        },
        template: '<div><span>\'value\' is expected to be resolved in scope {{expected}}, and is resolved in scope </span><span ng-transclude></span></div>'
    };
})

还有 HTML:

<div ng-controller="main">
    <inner expected="value">
        <span>{{value}}</span>
    </inner>
    <hr/>
    <outer expected="value">
        <span>{{value}}</span>
    </outer>
</div>

&lt;inner&gt;&lt;/inner&gt; 元素内{{value}} 在父范围内被评估为“main”(如预期的那样)。然而,在&lt;outer&gt;&lt;/outer&gt; 元素内部{{value}}outer 的隔离范围内被评估为“外部”(不是预期的)。这样指令的模板就可以影响到被转入的内容被解析的范围!

有没有办法解决这个问题?

【问题讨论】:

  • 为什么要使用隔离作用域?
  • 这样该指令可以在任何地方重用,而不会与其父范围发生意外交互。
  • 但是您的问题是关于与父范围交互的?
  • 转入的内容应该在父范围内解析(如角度文档所述),但指令本身不应与父范围交互(如角度文档建议)。
  • 你能告诉我什么角度文档推荐隔离范围吗?我想你可能误解了它的目的。

标签: javascript angularjs scope nested transclusion


【解决方案1】:

这真的很糟糕! Angular 只在孤立的范围内调用一个父级,如果它没有找到它需要的东西,它就会停止查找。要解决这个问题,您可以像这样手动调用作用域的父级:

controller: function ($scope) {
    $scope.value = $scope.$parent.value || '"outer"';
}

这将“让”他看起来更上一层楼。

【讨论】:

  • 这可行,但我正在寻找更灵活的解决方案。这些指令不一定知道它们将嵌套多深,或者要链接多少 .$parents。
【解决方案2】:

经过一番修改,我找到了解决方案。我创建了两个新指令来替换默认的ng-transcude,以及一个存储指令之间共享状态的辅助服务。它们一起实现了我正在寻找的深度嵌入。

首先将 $transclude 存储到服务中;它必须在每个可以在模板中赋予可转换内容的指令中使用:

controller: ['$transclude', 'TransclusionHelper', function($transclude,TransclusionHelper) {
    TransclusionHelper.setTransclusionFn($transclude);
}],

第二个执行将内容嵌入到其最终位置;它不需要用在只将其嵌入内容传递给孩子的指令中:

link: ['$element','TransclusionHelper', function($element,TransclusionHelper) {
    TransclusionHelper.transclude(function(clone) {
        $element.empty();
        $element.append(clone);
    });
}],

服务中需要一些技巧来管理状态;如果在调用transclude 之前多次调用setTransclusionFn,则在调用transclude 时只应存储和使用第一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多