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

时间:2013-04-04 18:53:26

标签: angularjs angularjs-directive angularjs-scope

我的指令设置如下:

<div data-directive-a data-value="#33ff33" data-checked="true">
  <div data-directive-b></div>
</div>
  • 我正在使用transclusion来确保directiveB呈现。
  • directiveA有一个复选框,用于在检查时更改某些值。
  • 此值需要在directiveAdirectiveB的范围内访问。

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

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

-

更深入一点: directiveA的'内容'(被转录到其中的内容)并不总是directiveB。其他类似directiveB的指令也会在那里结束。 directiveB“类型”将始终在directiveA内使用。

2 个答案:

答案 0 :(得分:12)

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

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

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

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

现在在directiveB,您可以使用ng-model="obj.attr"

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

答案 1 :(得分:7)

@Josh在他的回答中提到

  

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

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

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

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

由于要在directiveB的控制器中创建要与directiveA共享的对象,我们也无法使用属性在指令之间共享数据。


在指令中创建模型,然后将该模型共享给外部世界是非常典型的。通常,您需要在指令之外甚至在控制器之外定义模型(listen for a few minutes to Misko)。服务通常是存储模型/数据的好地方。控制器通常应该引用需要投影到与之关联的视图中的模型部分。

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

<强>控制

$scope.model = {value: '#33ff33', checkedState = true};

<强> HTML

<div ng-controller="NoTouchPrevSibling">
   <div data-directive-a data-value="model.value" data-checked="model.checkedState">
      <div data-directive-b></div>
   </div>

出于其他教学原因,我选择将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
    };
});

<强>作用域

scopes

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

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

scopes after interaction

请注意,Angular会处理更新隔离范围属性。正常JavaScript prototypal inheritance为directiveB的子范围提供对控制器范围(003)中model的访问。

Fiddle