使用Angular的Tabs指令

时间:2015-11-11 16:43:27

标签: angularjs

我正在创建一个Angular tabs指令,该指令将按如下方式应用:

<div id="tabs-with-directive" data-tabs>      
  <ul class="tabs">
    <li><a href="#" data-tabs-link="1">One</a></li>
    <li><a href="#" data-tabs-link="2">Two</a></li>
  </ul>            
  <div class="panes">
    <div data-tabs-pane="1" class="pane active">One</div>
    <div data-tabs-pane="2" class="pane">Two</div>
  </div>
</div>  

因此,单击One将显示第一个窗格,其中两个将显示第二个窗格,...

我创建了一个有效的Plunker example without using a directive

我有Plunker example using the directive I am trying to build

angular.module("app", [tabs]);   

(function(angular) {

  'use strict';

  angular.module('tabs', []);

  angular.module('tabs')
    .directive('tabs', tabsDirective);

  function tabsDirective() {
    return {
        scope: true,
        restrict: 'A',
        controller: tabsController
    };
  }

  function tabsController($scope) {

    $scope.tabs = [];

    this.addTab = function (tab) {
        $scope.tabs.push(tab);
    };

    this.isTabActive = function (link) {
      for(var i = 0; i < $scope.tabs.length; i++) {
        if ($scope.tabs[i].link == link)
          return $scope.tabs[i].active;
      }
      return false;
    };

    this.setTabToActive = function (link) {
      for(var i = 0; i < $scope.tabs.length; i++) 
        $scope.tabs[i].active = $scope.tabs[i].link == link;
    };        

  }

  tabsController.$inject = ['$scope'];

  angular.module('tabs')
    .directive('tabsLink', tabsLinkDirective);

  function tabsLinkDirective() {
    return {
        scope: false,
        restrict: 'A',
        require: '^tabs',
        link: function (scope, element, attributes, controller) {

          var tab = { link: attributes.link, active: "false" };
          controller.addTab(tab);

          element.bind('click', function () {
            controller.setTabToActive(attributes.link);
          });

          scope.$watch('tabs', function () {
            element.toggleClass('active', controller.isTabActive(attributes.link));
          });

        }
    };
  }

  angular.module('tabs')
    .directive('tabsPane', tabsPaneDirective);

  function tabsPaneDirective() {
    return {
        scope: false,
        restrict: 'A',
        require: '^tabs',
        link: function (scope, element, attributes, controller) {

            scope.$watch('tabs', function () {
              element.toggleClass('active', controller.isTabActive(attributes.pane));
            });

        }
    };
  }

})(angular);

不幸的是,这不起作用,我找不到我做错了什么。

有人可以帮帮我吗?

1 个答案:

答案 0 :(得分:1)

默认情况下,$watch会比较参考相等性。由于您正在修改数组中的对象,因此数组引用将保持不变,并且不会触发监视侦听器。

要监视对数组中对象的修改,您需要将true作为第三个参数传递:

scope.$watch('tabs', function() {
  element.toggleClass('active', controller.isTabActive(tab.link));
}, true);

以下内容:

attributes.link

在所有地方都应该替换为以下内容:

attributes.tabsLink

以下内容:

attributes.pane

应替换为:

attributes.tabsPane

我假设你希望其中一个标签开始处于活动状态。

以下您无法使用:

class="pane active"

由于没有任何标签模型将active设置为true,因此以下代码将剥离active类:

scope.$watch('tabs', function() {
  element.toggleClass('active', controller.isTabActive(attributes.tabsPane));
}, true);

如果您希望active类指示选项卡是否应该以活动状态启动,您可以添加以下内容:

if (element.hasClass('active')) {
  controller.setTabToActive(attributes.tabsPane);
}

请注意,这不会阻止多个标签作为活动标签启动,如果没有该标签,也不会将其设置为活动状态。

我强烈建议改变:

active: "false"

要:

active: false

而是使用严格的相等(===代替==

element.on不是AngularJS函数,不会为您触发摘要循环 - 这意味着数据绑定不会在UI中更新。

您需要手动执行此操作:

element.bind('click', function() {
  scope.$apply(function() {
    controller.setTabToActive(tab.link);
  });
});

演示: http://plnkr.co/edit/9nskxIR0DHaDuAEG9CfX?p=preview