可以使用$$ prevSibling来访问"transcluded"指令中的范围数据吗?

jlb*_*jlb 10 angularjs angularjs-directive angularjs-scope

我的指令设置如下:

<div data-directive-a data-value="#33ff33" data-checked="true">
  <div data-directive-b></div>
</div>
Run Code Online (Sandbox Code Playgroud)
  • 我正在使用transclusion来确保directiveB渲染.
  • directiveA 有一个复选框,用于在检查时更改某个值.
  • 这个值需要在directiveAdirectiveB范围内访问.

我设法做到了这一点,但只是通过引用$$prevSibling- 是否有更好的方法?

这是代码:http://jsfiddle.net/janeklb/yugQf/(在此示例中,单击复选框只是为了"清除"值)

-

更深入一点:(内容)directiveA(被转录到其中的内容)并非总是如此directiveB.其他类似directiveB的指令也会在那里结束.在directiveB"类型"总是会内使用directiveA.

Jos*_*ler 12

为避免将组件耦合太多,我会避免使用$$prevSibling.由于您的类似directiveB组件预计将在directiveA组件中使用,因此最佳解决方案是使用require.

.directive( 'directiveB', function () {
  return {
    require: '^directiveA',
    scope: true,
    link: function ( scope, element, attrs, directiveA ) {
      scope.obj = directiveA.getObj();
    }
  };
})
Run Code Online (Sandbox Code Playgroud)

^require表明在该指令的元素或DOM层次结构中它上面的任何元素上的某个地方是一个被调用的指令directiveA,我们想在其控制器上调用方法.

.directive( 'directiveA', function () {
  return {
    // ...
    controller: function ( $scope ) {
      // ...
      this.getObj = function () {
        return $scope.obj;
      };
    }
  };
})
Run Code Online (Sandbox Code Playgroud)

所以现在directiveB你可以使用ng-model="obj.attr".

这有很多变化,但考虑到问题的一般性,我觉得这是最好的方法.这是一个更新的小提琴:http://jsfiddle.net/yugQf/7/.


Mar*_*cok 7

@Josh在他的回答中提到了

由于您的类似directiveB组件预计将在directiveA组件中使用,因此最佳解决方案是使用require.

我一直在玩这个,我相信控制器directiveA就是唯一的解决方案(所以+1 Josh).这是使用OP的小提琴的范围: 范围图片

(反转棕色箭头,你有$$ previousSibling而不是$$ nextSibling.)

除此之外$$previousSibling,范围004没有隔离范围003的路径.请注意,范围004是directiveA创建的转换范围,并且由于directiveB不创建新范围,因此也使用此范围directiveB.

由于您要共享的对象directiveB是在directiveA控制器中创建的,因此我们也不能使用属性在指令之间共享数据.


在指令中创建模型,然后将该模型共享给外部世界是相当不典型的.通常情况下,您需要在指令之外甚至在控制器之外定义模型(听Misko几分钟).服务通常是存储模型/数据的好地方.控制器通常应该引用需要投影到与之关联的视图中的模型部分.

为简单起见,我将在控制器上定义模型,然后指令将以正常方式访问此模型.出于教学目的,directiveA仍将使用隔离范围,并将directiveB使用scope: new@Josh的答案创建新的子范围.但是任何类型(隔离,新子,没有新范围)和组合都可以工作,现在我们已经在父范围中定义了模型.

Ctrl:

$scope.model = {value: '#33ff33', checkedState = true};
Run Code Online (Sandbox Code Playgroud)

HTML:

<div ng-controller="NoTouchPrevSibling">
   <div data-directive-a data-value="model.value" data-checked="model.checkedState">
      <div data-directive-b></div>
   </div>
Run Code Online (Sandbox Code Playgroud)

出于其他教学原因,我选择将directiveA两个模型属性作为单独的属性传递,但整个模型/对象也可以传递.由于directiveB将创建子范围,因此它不需要传递任何属性,因为它可以访问所有父/控制器范围属性.

指令:

app.directive('directiveA', function () {
    return {
        template: '<div>' 
            + 'inside parent directive: {{checkedState}}'
            + '<input type="checkbox" ng-model="checkedState" />'
            + '<div ng-transclude></div>'
            + '</div>',
        transclude: true,
        replace: true,
        scope: {
              value: '=',
              checkedState: '=checked'
            },
    };
});
app.directive('directiveB', function () {
    return {
        template: '<div>' 
            + '<span>inside transcluded directive: {{model.checkedState}}</span>'
            + '<input type="text" ng-model="model.value" />'
            + '</div>',
        replace: true,
        scope: true
    };
});
Run Code Online (Sandbox Code Playgroud)

范围:

领域

请注意,directiveB的子范围(006)继承自directiveA的transcluded范围(005).

单击复选框并更改文本框中的值后:

交互后的范围

请注意,Angular会处理更新隔离范围属性.正常的JavaScript原型继承赋予directiveB的子范围访问model控制器范围(003).

小提琴