2013-03-07 130 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