2013-03-07 58 views
1

我正在与一个问题斗争,无法弄清楚为什么会发生。Angularjs中的指令如何工作?

我有一个模块(portfolioModule),服务(菜单)和指令(niMenu)。该指令应呈现一个菜单项及其子项。

HTML:

<div ng-app="portfolioModule"> 
    <script id="menuItem" type="text/ng-template"> 
    <li> 
     <a>{{item.name}}</a> 
     <ul> 
      <li ng-repeat="item in menu.getKids(item.id)" ng-include="'menuItem'"></li> 
     </ul> 
    </li> 
    </script> 

    <div> 
     <div ni-menu="test">test1</div> 
    </div> 
</div> 

的JavaScript:

var portfolioModule = angular.module('portfolioModule', []); 

portfolioModule.factory('Menu', function() { 
     var items = [ 
      { 
       "parent_id": null, 
       "id": 1, 
       "name": "foo" 
      }, { 
       "parent_id": 1, 
       "id": 2, 
       "name": "foo-bar" 
      } 
     ]; 
     this.getKids = function(parent_id) { 
      var result = []; 
      parent_id = parent_id || null; 

      console.log('getKids', parent_id); 
      angular.forEach(items, function(value) { 
       if (value.parent_id === parent_id) { 
        result.push(value); 
       } 
      }); 
      return result; 
     }; 

     return this; 
    } 
); 

portfolioModule.directive('niMenu', function(Menu) { 
     var niMenu; 
     return niMenu = { 
      template: '<ul ng-include="\'menuItem\'" ng-repeat="item in menu.getKids()"></ul>', 
      restirt: 'A', 
      link: function(scope, element, attrs) { 
       console.log('link'); 
       scope.menu = Menu; 
      } 
     }; 
    } 
); 

工作演示:http://jsfiddle.net/VanSanblch/Ng7ef

在html中,我通过ni菜单调用niMenu。该指令有一个模板和一个链接功能,将Menu-service放入模块范围。在指令的模板中,我使用Menu.getKids()并获取所有顶级项目。之后,在ng-include使用的模板中,我调用Menu.getKids(item.id)并获取特定项目的所有子项。

除了一个小细节外,一切都很好。如果您打开控制台,则可以观察到getKids的调用比我预期的要多得多。例如,对于两个元素的数组,getKids调用的数量是9。

有人能解释为什么在地球上发生?

+1

糟糕 - 你没有链接到你的小提琴。 :-) – 2013-03-07 05:15:00

+1

@JoshDavidMiller固定。 – 2013-03-07 05:16:42

回答

6

好了,所以它的执行不止一次的原因是因为这是消化周期是如何工作的:它不断地执行所有视图表达式(如你传递给ngRepeat的一个),直到它表达没有变化。有关更多信息,请参见this answer,但要注意的是:它总是至少执行一次,但通常更多。

使用ngRepeat,你一般要避免从一个功能,因为它负面影响性能获取数据;为什么在数据从未改变时多次调用相同的函数?更好的方法是让您的控制器(或本例中的指令)执行您的函数并将结果存储在范围中,因此您的ngRepeat看起来像ng-repeat="item in items"而不是ng-repeat="item in getItems()"

不幸的是,这意味着你不得不调整你有你的指令工作的方式。无论如何,这是一个好主意,因为你的指令可以被重写得更简单 - 例如,你不需要任何ngInclude。

你想要做什么是创建两个指令,因为你有两个模板:一个代表整体的菜单和一个代表一个子项(其中,反过来,可以有子项)。 menu指令应该在顶层菜单项上重复,为每个菜单项绘制一个menuItemmenuItem指令应该检查孩子,并在必要时重复这些操作,更多menuItem。等等。下面是Andy Joslin为你创建一个递归目录的例子:http://plnkr.co/edit/T0BgQR

要实现这样的超越了这个问题的范围,而是采取了刺它,并张贴了新的问题,如果你需要帮助。

祝你好运!

+0

太棒了!这绝对是澄清一切。谢谢您的回答。 – vansanblch 2013-03-07 08:37:47

+0

伟大的指示!给任何想要在重击者中使用这个例子的人留下一个提示。定义'choiceDirective'是避免使用缩小器和uglifier时出现问题的长手段。因此,不用'app.directive('choice',function($ compile)''使用'app.directive('choice',['$ compile',function($ compile)'。不要忘记你需要在指令方法的末尾添加一个结束的']'。 – 2015-10-22 11:46:59