2012-12-20 61 views
27

所以,如果我有100裏的應該有NG-點擊一個UL在每個L1或有對事件綁定到UL和它委託給李的那種jQuery不會有什麼辦法?這會好還是壞?我們有100個活動,還是最終只有一個活動?角NG-click事件代表團

+0

我的一個朋友指出了這一點: http://plnkr.co/edit/uC49BsKmvvDvQNJ72r0v?p=preview 有可能用飛機achiev這個角度 – Vengarioth

回答

21

看起來角度沒有做中繼器的事件委託。有人打開issue on github about it。這個論點是,如果它實際上導致更好的表現。

可能有一種解決方法,但它需要jQuery。它包括創建一個用於父元素的特殊指令,並在其dom節點上註冊偵聽器。

下面是一個例子,傳遞函數名被點擊一個子節點時調用,並且還通過了一個選擇,以幫助識別聽其子節點。 由於角度的jQuery的實現只給了我們bind方法 - 這是僅限於註冊事件偵聽器的實際元素 - 我們需要加載jQuery來訪問無論是ondelegate方法。

HTML

<ul click-children='fun' selector='li'> 
    <li ng-repeat="s in ss" data-index="{{$index}}">{{s}}</li> 
</ul> 

定義的功能被在控制器定義,它預計要傳遞的索引

$scope.fun = function(index){ 
    console.log('hi from controller', index, $scope.ss[index]);  
}; 

的指令使用$parse的表達式轉換成將被調用的函數來自事件監聽者。

app.directive('clickChildren', function($parse){ 
    return { 
    restrict: 'A', 
    link: function(scope, element, attrs){  
     var selector = attrs.selector; 
     var fun = $parse(attrs.clickChildren); 
     element.on('click', selector, function(e){  
     // no need to create a jQuery object to get the attribute 
     var idx = e.target.getAttribute('data-index');   
     fun(scope)(idx);   
     }); 
    } 
    }; 
}); 

Plunker:http://plnkr.co/edit/yWCLvRSLCeshuw4j58JV?p=preview


注:功能可以委託給使用隔離示波器{fun: '&'},這是值得一試的指令,但是這會增加複雜性。

+0

嘿感謝你非常jm-您回答。我一直很好奇,如果這將是更多的穿孔或不。去運行一些js perfs來查看id我可以及時發現它的差異。這個解決方案非常酷! – climboid

+1

您還需要偵聽'$ destroy'事件,以從'element'中刪除事件偵聽器。否則,我認爲元素從DOM中移除時會發生內存泄漏。 – Greg

+0

喲需要使用'e.currentTarget'而不是'e.target'。 'e.target'是點擊下的元素。 'e.currentTarget'是事件附加的元素(甚至委派事件)。例如,如果html是''且委託選擇符是'a',那麼'e.target'將是'span'元素,'e.currentTarget'將是'a'元素。 – djxak

6

工作在這裏下車JM-的例子,我寫了這個指令的更簡潔和靈活的版本。以爲我會分享。幸得jm-;)

我的版本試圖調用函數名作爲$範圍[FN](即數據),或優雅地失敗。

它從被點擊的元素傳遞一個可選的json對象。這使您可以使用Angular表達式並將多個屬性傳遞給被調用的方法。

HTML

<ul delegate-clicks="handleMenu" delegate-selector="a"> 
    <li ng-repeat="link in links"> 
    <a href="#" data-ng-json='{ "linkId": {{link.id}} }'>{{link.title}}</a> 
    </li> 
</ul> 

的Javascript

控制器方法

$scope.handleMenu = function($event, data) { 
    $event.preventDefault(); 
    $scope.activeLinkId = data.linkId; 
    console.log('handleMenu', data, $scope); 
} 

指令構造

// The delegateClicks directive delegates click events to the selector provided in the delegate-selector attribute. 
// It will try to call the function provided in the delegate-clicks attribute. 
// Optionally, the target element can assign a data-ng-json attribute which represents a json object to pass into the function being called. 
// Example json attribute: <li data-ng-json='{"key":"{{scopeValue}}" }'></li> 
// Use case: Delegate click events within ng-repeater directives. 

app.directive('delegateClicks', function(){ 
    return function($scope, element, attrs) { 
    var fn = attrs.delegateClicks; 
    element.on('click', attrs.delegateSelector, function(e){ 
     var data = angular.fromJson(angular.element(e.target).data('ngJson') || undefined); 
     if(typeof $scope[ fn ] == "function") $scope[ fn ](e, data); 
    }); 
    }; 
}); 

我喜歡聽到的反饋,如果有人願意貢獻。

因爲我萃取此從更復雜的應用我沒有測試handleMenu方法。

+0

好的工作。使用georg對「解析對象點符號來檢索對象的值」的回答來查看我的增強功能。 – BillVo

0

從BradGreens的delegateClicks開始,我修改了some code from georg,它允許我把handleMenu函數放在$ scope的更深處(例如$ scope.tomato.handleMenu)。

app.directive('delegateClicks', function() { 
    return function ($scope, element, attrs) { 
     var fn = attrs.delegateClicks.split('.').reduce(function ($scope, p) { return $scope[p] }, $scope); 
     element.on('click', attrs.delegateSelector, function (e) { 
      var data = angular.fromJson(angular.element(e.target).data('ngJson') || undefined); 
      if (typeof fn == "function") fn(e, data); 
     }); 
    }; 
});