2013-08-20 91 views
7

我有以下代码。它通过JSON循环来产生一个嵌套的ul列表。我有一个单击事件,它执行绑定到锚标记的函数toggleNav()。我不知道为什么click事件绑定了两次元素。另外我对角度很陌生,有没有解释这个概念的文档?谢谢!Angular JS:为什么我的点击事件触发两次?

define([ 
'/assets/angularapp/AppDirectives.js', 
'highstock' 
], function (directives) { 
directives.directive('collection', function() { 
    return { 
     restrict: "E", //declare by element 
     replace: true, 
     scope: { 
      collection: '=' 
     }, 
     template: "<ul class=\"nav nav-list tree\"><member ng-repeat=\"member in collection\" member=\"member\"></member></ul>" 
    } 
}) 

directives.directive('member', function ($compile) { 

    return { 
     restrict: "E", 
     replace: true, 
     scope: { 
      member: '=' 
     }, 
     template: "<li ng-show=\"member.open\"><span><input type=\"checkbox\" ng-model=\"member.selected\" class=\"sideChkbox\"><a class=\"tree-toggle\" ng-click=\"toggleNav()\"><i class=\"icon-chevron-right\"></i>{{member.data}}</a></span></li>", 
     controller: function($scope, $element){ 
      $scope.toggleNav = function(){ 
       angular.forEach($scope.member.children,function(child,key){ 
        if(child.open==true){ 
         alert("a") 
         child.open=false; 
        } else { 
         child.open=true; 
         alert("b") 

        } 

       }) 

      } 
     }, 
     link: function (scope, element, attrs) { 
      if (angular.isArray(scope.member.children)) { 
       element.append("<collection collection='member.children'></collection>"); 
       $compile(element.contents())(scope) 
      } 
     } 
    } 
}) 
+0

你可以把小提琴放在一起显示这一点,我没有看到任何明显的,应该触发两个调用处理程序。但在使用指令后能够检查DOM可能会导致一些洞察。你也确定你不只是在处理程序中获得循环的多次迭代,而是实际上多次调用处理程序? – shaunhusain

+0

你在说foreach循环触发两个警报吗?它可能包含两个元素,但函数仍然绑定一次。 – zsong

+1

我做了一个小提琴来检查这个问题,我确切地看到你在说什么,老实说不知道为什么会发生这种情况:http://jsfiddle.net/rEz52/1/ – shaunhusain

回答

13

这是因为你编译element.contents(),包括<一个>与NG-点击,这应该是已经编译。当你调用手动编译时,它会被再次编译。

您可以通过此修复:

... 
    if (angular.isArray(scope.member.children)) { 
     var newMemEL = angular.element("<collection collection='member.children'></collection>"); 
     element.append(newMemEL); 
     $compile(newMemEL)(scope); 
    } 
    ... 

它看起来就像你正在试图创建一个TreeView,在这种情况下,这将是更好地使用ngInclude而不是创建自定义的指令,看看这plunker,请注意,它不会与角1.2.0rc1由于这种issue

2

@ Mr.DucNguyen的答案是正确的工作,但如果你不想再操作DOM,你可以接近它的另一种方式。

在链接函数期间将元素标记为已完成,因此当它尝试再次链接时它失败。

link: function (scope, element, attrs) { 
    // stop an already linked element from continuing 
    if (element.attr('collection-linked')) { 
     return; 
    } 
    // otherwise, add a completed flag to this element 
    element.attr('collection-linked', true); 

    // continue your linking ... 
}