与兄弟指令沟通

Cod*_*er1 22 angularjs angularjs-directive

目标:使用指令在两个兄弟元素之间进行通信来创建行为(每个元素都有自己的指令).

在示例中使用的行为:默认情况下隐藏文章内容.单击标题时,我希望显示相关的文章内容.

catch:相关的article元素需要彼此关联,而不是嵌套在单个父元素或指令中.

<div article="article1">this is my header</div>
<div id="article1" article-content>this is content for the header above</div>

<div article="article2">this is my header</div>
<div id="article2" article-content>this is content for the header above</div>
Run Code Online (Sandbox Code Playgroud)

我知道将内容放在article指令中更容易,但是这个问题是要找出如何解决这样的情况.

内容指令能否以某种方式将自身传递给相关的文章指令?

这段代码现在不是很有用,但它是一个起点.我怎么做到这一点?

.directive('article', function(){
  return {
    restrict: "A",
    controller: function($scope) {
      $scope.contentElement = null;
      this.setContentElement = function(element) {
        $scope.contentElement = element;
      }
    },
    link: function(scope, element) {
      element.bind('click', function(){
        // Show article-content directives that belong
        // to this instance (article1) of the directive
      }
    }
  }
}
.directive('articleContent', function(){
  return {
    require: "article",
    link: function(scope, element, attrs, articleCtrl) {
      // Maybe reference the article i belong to and assign element to it?
      // I can't though because these are siblings.
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Ian*_*rty 32

没有任何指令require选项允许您要求兄弟指令(据我所知).你只能:

  • 要求在元素上使用 require: "directiveName"
  • 告诉angular使用搜索DOM树 require: "^directiveName"
  • 或者require: "^?directiveName"如果您不一定需要父控制器
  • 或者require: "^\?directiveName"如果您不一定需要父DOM包装器

如果你想兄弟姐妹进行兄弟姐妹的沟通,你必须将它们放在一些父DOM元素中,并使用指令控制器充当他们沟通的API.如何实现这在很大程度上取决于手头的背景.

以下是Angular JS(O Reilly)的一个很好的例子

app.directive('accordion', function() {
  return {
    restrict: 'EA',
    replace: true,
    transclude: true,
    template: '<div class="accordion" ng-transclude></div>',
    controller: function() {

      var expanders = [];

      this.gotOpened = function(selectedExpander) {
        angular.forEach(expanders, function(expander) {
          if(selectedExpander != expander) {
            expander.showMe = false;
          }
        });
      };

      this.addExpander = function(expander) {
        expanders.push(expander);
      }

    }
  }
});

app.directive('expander', function() {
  return {
    restrict: 'EA',
    replace: true,
    transclude: true,
    require: '^?accordion',
    scope: { title:'@' },
    template: '<div class="expander">\n  <div class="title" ng-click="toggle()">{{ title }}</div>\n  <div class="body" ng-show="showMe" \n       ng-animate="{ show: \'animated flipInX\' }"\n ng-transclude></div>\n</div>',
    link: function(scope, element, attrs, accordionController) {
      scope.showMe = false;
      accordionController.addExpander(scope);

      scope.toggle = function toggle() {
        scope.showMe = !scope.showMe;
        accordionController.gotOpened(scope);
      }
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

用法(玉石模板):

accordion
    expander(title="An expander") Woohoo! You can see mme
    expander(title="Hidden") I was hidden!
    expander(title="Stop Work") Seriously, I am going to stop working now.
Run Code Online (Sandbox Code Playgroud)

  • 这是一个完美的例子,应该标记为答案. (2认同)

Iva*_* V. 10

或者你可以创建一个servicejust for directive通信,special servicevs的一个优点require是你的指令不依赖于它们在html结构中的位置.

  • `service C`用于促进`service A`和`service B`之间的通信.所以你在`service A`和`service B`中注入`service C`.实际代码的解决方案之一是"服务C"保持对"服务A"和"服务B"的引用.所以从`service A`里面你可以像这样与`service B`进行通信:`serviceC.getServiceB().methodOnServiceB()` (3认同)
  • 另一种解决方案是使用"服务C"调度事件,使得"A"和"B"或任何其他具有"服务C"注入的服务,可以监听这些事件并采取相应的行动. (3认同)

Cha*_*ani 0

如果有文章及其内容的列表,我们可以使用 ng-repeat 来完成,无需任何指令

<div ng-repeat="article in articles">
   <div article="article1" ng-click='showContent=true'>{{article.header}}</div>
   <div id="article1" article-content ng-show='showContent'>{{article.content}}</div>
</div>
Run Code Online (Sandbox Code Playgroud)

所以你需要在控制器中定义文章模型。我们正在利用 ng-repeat 创建的本地范围。

更新:根据您的反馈,您需要将它们链接在一起。您可以尝试

<div article="article1" content='article1'>this is my header</div>
<div id="article1" article-content>this is content for the header above</div>
Run Code Online (Sandbox Code Playgroud)

并在您的指令中

使用

link: function(scope, element,attrs) {
      element.bind('click', function(){
        $('#'+attrs.content).show();
      }
    }
Run Code Online (Sandbox Code Playgroud)

最后的方法可能是使用$rootScope.$broadcastscope.$on方法在控制器之间进行通信。但在这种方法中,您需要跟踪消息的来源以及谁是需要处理该消息的预期收件人。