访问指令的隔离范围与嵌入的内容

Posted

技术标签:

【中文标题】访问指令的隔离范围与嵌入的内容【英文标题】:Access directive's isolate scope from within transcluded content 【发布时间】:2013-04-16 19:42:43 【问题描述】:

我不确定这是否真的可行,但我本质上是想要 AngularJS 中的 '&' 隔离范围的反向。这是一个Plunkr 来演示。

基本上,我设置了一个自定义指令来提供一些可重用的 html。它利用ng-transclude 允许在其中呈现一些外部内容。但是,我发现了一种情况,我想从代码的嵌入部分访问已在指令的隔离范围上设置的函数。

所以基本上我有一些看起来像:

<div ng-controller="MainController">

    <!-- The directive -->
    <div some-custom-directive>

        <!-- Button 1 that invokes a method within the controller scope -->
        <button id="button1" ng-click="invoke1()">Invoke from Controller</button>

        <!-- Button 2 that invokes a method on the isolate scope for the custom directive -->
        <button id="button2" ng-click="invoke2()">Invoke from Isolate Scope</button>
    </div>
</div>

有人知道这是否真的可能吗?

更新

根据@Mark Rajcok 的回答,$scope 上的$$prevSibling 可用于从嵌入内容中访问指令的隔离范围。但是,我已经更新了上面的 Plunkr 以从 ng-repeat 指令中尝试此操作,但该指令不起作用。我假设该重复中的项目不继承范围。

【问题讨论】:

【参考方案1】:

这是一个解决您当前问题的解决方案。我不确定您要做什么。但据我所知,没有办法从外部范围调用隔离范围内的东西。当然,您可以在隔离作用域和外部作用域之间设置双向绑定变量,更改外部作用域中的变量并在隔离作用域上 $watch (这将像事件机制一样工作)......这是一个做你想做的事的方式..如果你坚持的话。

另外,有一种机制可以从隔离作用域调用外部作用域上的函数。有点像回调。

看到这个http://plnkr.co/edit/5MT4vo9qXtV6nQikfEiH?p=preview

【讨论】:

【参考方案2】:

虽然可能,但我提出的解决方案是一个 hack,因为它使用范围内部变量 $$prevSibling

在您被嵌入的内容中,您处于被嵌入的范围内。该指令的隔离和嵌入范围是同级的。要从嵌入范围到隔离范围,可以使用$$prevSibling。 (要从隔离作用域到转入作用域,可以使用$$nextSibling。)

所以,这个 hack 会起作用:

<a href="" ng-click="$$prevSibling.action()">Invoke the Directive Action</a>

要在控制器范围内调用方法,您需要指定使用&amp;,正如@ganaraj 已经演示的那样:

<content-presenter controller-action="action()">

然后在你的指令中:

scope:  controllerAction: '&' ,
template: ... +
   '<button ng-click="controllerAction()">Trigger Ctrl action()</button>' ...

Plunker


使用 ng-repeat(请参阅 Samuel 的评论),每个项目都会创建嵌入范围的子范围。在下图中,我只显示了一个item 以保持图片更小。反转 $$prevSibling 的 $$nextSibling 棕色箭头。

因此,从 ng-repeat 子作用域到隔离作用域上定义的方法 action() 的技巧是

<div ng-repeat="item in items" ng-click="$parent.$$prevSibling.action()">

Angular v1.3+ 更新

从 Angular v1.3 开始,transcluded 作用域现在是指令的isolate 作用域的子对象——它们不再是兄弟。所以要从嵌入范围到隔离范围,请使用$parent

使用 ng-repeat,每个项目仍然创建一个被嵌入范围的子范围:

但是要从 ng-repeat 子范围中访问在隔离范围上定义的方法 action(),我们现在使用

<div ng-repeat="item in items" ng-click="$parent.$parent.action()">

【讨论】:

干杯,成功了。但是,我发现它在ng-repeat 中不起作用(我假设因为每个项目都没有从控制器继承$scope。无论如何每个项目都可以访问$$prevSibling?我已经更新了以上Plunkr举个例子。 太棒了,就像一个魅力!感谢您的图表,非常有用。 您知道是否可以在视图代码中为$parent 链定义一个有意义的名称?类似ng-let="isolateScope = $parent.$parent"【参考方案3】:

据我了解,将ng-repeat 添加到元素会创建一个新范围,以便正确绑定重复内容。您可能需要在该链中添加一个 $parent,例如 $parent.$$nextSibling,以便升级到与指令的隔离范围相邻的级别。

【讨论】:

以上是关于访问指令的隔离范围与嵌入的内容的主要内容,如果未能解决你的问题,请参考以下文章

在 AngularJS 中从没有隔离范围的指令调用控制器函数

AngularJS中带有ng-repeat范围的指令隔离范围

为啥我应该在 AngularJS 中使用隔离范围指令?

具有隔离范围的嵌套指令中的双向绑定延迟

如何在 AngularJS 中对隔离范围指令进行单元测试

使用隔离范围时,从指令调用控制器的功能?