web-dev-qa-db-ja.com

Angular ng-clickイベントの委任

したがって、100個のliを持つulがある場合、各liにng-clicksが必要ですか、それとも、イベントをulにバインドして、それをliの種類のjqueryに委任する方法がありますか?これは良いですか悪いですか?私たちは100のイベントを持っていますか、それとも最後には1つのイベントだけですか?

28
climboid

angularはリピーターとのイベント委任を行いません。誰かが githubの問題について)をオープンしました 。議論は、それが実際にパフォーマンスの向上につながるかどうかです。

回避策があるかもしれませんが、jQueryが必要になります。これは、親要素で使用される特別なディレクティブを作成し、そのdomノードにリスナーを登録することで構成されます。

子ノードがクリックされたときに呼び出される関数名が渡される例と、リッスンする子ノードを識別するためのセレクターが渡される例を次に示します。 angularのjquery実装はbindメソッドのみを提供するため-実際の要素へのイベントリスナーの登録に限定されています-onまたはdelegate 方法。

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);        
      });
    }
  };
});

プランカー: http://plnkr.co/edit/yWCLvRSLCeshuw4j58JV?p=preview


注:関数は分離スコープ{fun: '&'}を使用してディレクティブに委任できます。これは一見の価値がありますが、これにより複雑さが増します。

21
jaime

ここでjm-の例に基づいて、このディレクティブのより簡潔で柔軟なバージョンを作成しました。共有したいと思いました。クレジットはjm-に送られます;)

私のバージョンでは、関数名を$ scope [fn](e、data)として呼び出そうとするか、正常に失敗します。

クリックされた要素からオプションの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メソッドはテストしませんでした。

6
BradGreens

GitHubの問題 によると、イベント処理を委任することによるパフォーマンス上の利点はありません。

単にng-clickディレクティブ、アイテム、$index$event

<ul>
   <li ng-repeat="item in collection"
       ng-click="lineClicked(item, $index, $event)">
      {{item}}
   </li>
</ul>
$scope.lineClicked = function(item, index, event) {
    console.log("line clicked", item, index);
    console.log(event.target)
});

詳細については、

0
georgeawg

上記のBradGreensのdelegateClicksから始めて、 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);
        });
    };
});
0
BillVo