子指令和父指令应该如何在AngularJS中进行通信?

时间:2015-12-12 22:08:38

标签: angularjs angularjs-directive

我无法理解如何在AngularJS中使用MVC。 我正在写一个简单的标签手风琴。

假设我有这种HTML结构:

<my-tabs>
     <tab title="Tab One">
         <div>content 1</div>
     </tab>
     <tab title="Tab Two">
       <div>Tab 2 content</div>
     </tab>
     <tab title="Tab Three">
        <div>Tab 3 content</div>
     </tab>
</my-tabs>

这是我的JS。我有主要指令和子指令:

directive("myTabs", function () {
    return {
        restrict: "E",
        transclude: true,
        replace: true,
        scope: {},
        template:
            "<ul></ul>",
        link: function (scope, element, attrs) {

            var arrayOfTabs = element.find("li");
        },
        controller: function () {}
    };
})
              .directive('tab', function () {
                  return {
                      require: "^myTabs",
                      restrict: "E",
                      transclude: true,
                      replace: true,
                      scope: {
                          title: "@"
                      },
                      template:
                          "<li>" +
                          "  <h1 class='title'>{{title}}</h1>" +
                          "  <div class='content' ng-transclude></div>" +
                          "</li>",
                      link: function (scope, element, attrs) {

                          scope.openTab = function()
                          {
                              var contentWidth = element.attr("content-width");
                              element.css('width', contentWidth);
                          }

                          scope.closeTab = function ()
                          {
                              var contentWidth = element.attr("content-width");
                              element.css('width', tabCloseWidth);
                          }

                      }
                  };
              })

我真正不明白的是: tab指令只能打开/关闭它自己,而myTabs指令是打开所选择的指令并关闭所有其他指令的指令。但是 - 他们如何沟通?我不希望“tab”在每个选择上触发事件,告诉“myTabs”打开选定的选项卡并关闭所有其他选项。对于这两个指令,必须有比$ watch或$ on / $ broadcast更好的方式来互相交流吗?我在这里想念的是什么?当用户点击标签时,我想让“myTabs”控制并设置打开哪个标签以及关闭哪个标签,但他怎么知道?每个人都有孤立的范围。

2 个答案:

答案 0 :(得分:1)

指令之间有一些沟通方式:

  • events($ emit / $ broadcast)
  • 观察者模式
  • “控制器方法调用”(不确定名称是什么,请参阅下面的说明)。

你想要使用的东西并不容易,但让我解释一下:

  1. 作为link方法的第4个参数,您可以访问指令的控制器
  2. myTabsController添加方法,通过传递选项卡的范围将每个选项卡注册到数组中。 (我首先认为这是不好的做法,但我已经检查过angular-ui-bootstrap手风琴的源代码,他们也是这样做的。所以这应该没问题。)
  3. 然后在open方法中,您可以调用closeOthers的{​​{1}}方法并传递当前打开的标签(=范围),然后它将使用{{1}关闭其他元素} loop。
  4. 请查看下面的演示或此jsfiddle

    myTabsController
    angular.forEach
    angular.module('demoApp', [])
      .controller('MainController', function($scope) {
        $scope.open = true;
        $scope.oneAtATime = true;
      })
      .constant('tabsConfig', {
      	closeOthers: true
    	})
      .directive("myTabs", function() {
        return {
          restrict: "E",
          transclude: true,
          replace: true,
          scope: {
          },
          template: "<ul ng-transclude></ul>",
          link: function(scope, element, attrs) {
            //var arrayOfTabs = element.find("li");
          },
          controller: function($scope, $attrs, tabsConfig) {
            this.tabs = [];
    
            this.addTab = function(tab) {
              this.tabs.push(tab);
            };
    
            this.closeOthers = function(openTab) {
            	var closeOthers = angular.isDefined($attrs.closeOthers) ?
          		$scope.$eval($attrs.closeOthers) : tabsConfig.closeOthers;
              
        			if (closeOthers) {
                angular.forEach(this.tabs, function(tab) {
                  if (!angular.equals(tab, openTab)) {
                    //console.log(tab);
                    tab.closeTab();
                  }
                });
              }
            };
          }
        };
      })
      .directive('tab', function() {
          return {
            require: "^myTabs",
            restrict: "E",
            transclude: true,
            replace: true,
            scope: {
              title: "@",
              open: '='
            },
            template: '<li ng-click="toggle()">' +
              "  <h1 class='title'>{{title}}</h1>" +
              "  <div class='content' ng-transclude></div>" +
              "</li>",
            link: function(scope, element, attrs, myTabsCtrl, ngTransclude) {
    
              myTabsCtrl.addTab(scope);
              //console.log('ctrl', myTabsCtrl);
              //console.log(scope.open);
              if (!scope.open) {
                closeTab();
              }
              scope.toggle = function() {
                //scope.open = !scope.open;
    
                if (scope.open) {
                  closeTab();
                } else {
                  openTab();
                  myTabsCtrl.closeOthers(scope);
                }
              };
              scope.openTab = openTab;
              scope.closeTab = closeTab;
    
              function openTab() {
                /*var contentWidth = element.attr("content-width");
                element.css('width', contentWidth);*/
                element.find('div').css('display', 'block');
                scope.open = true;
              }
    
              function closeTab() {
                /*
                  var contentWidth = element.attr("content-width");
                  element.css('width', tabCloseWidth);*/
                element.find('div').css('display', 'none');
                scope.open = false;
              }
    
            }
          };
        });

答案 1 :(得分:0)

您需要了解angularjs中的范围 - https://docs.angularjs.org/guide/scope

现在两个指令都有'隔离'范围scope: {}意味着他们'彼此不了解'除了'myTabs'可以使用属性'title'将标题传递给'tab'这一事实。

这应该解释您需要知道的所有https://github.com/angular/angular.js/wiki/Understanding-Scopes