Подтвердить что ты не робот

Angular Деление события ng-click

Итак, если у меня есть ul с 100 li, должно ли быть ng-clicks в каждом li или есть способ связать событие с ul и делегировать его в li-тип того, что делает jquery? Будет ли это лучше или хуже? Есть ли у нас 100 событий или это только одно событие в конце?

4b9b3361

Ответ 1

Кажется, что angular не выполняет делегирование событий с повторителями. Кто-то открыл вопрос о github об этом. Аргументом является то, что это фактически приводит к повышению производительности.

Может возникнуть обходное решение, но для этого потребуется jQuery. Он состоит из создания специальной директивы для использования в родительском элементе и регистрации слушателя на его dom node.

Вот пример, которому передается имя функции, которое вызывается при нажатии дочерних элементов node, а также передается селектор, который помогает идентифицировать, какие дочерние узлы прослушивать. Так как реализация angular jquery дает нам только метод bind, который ограничивается регистрацией прослушивателей событий фактическому элементу - нам нужно загрузить jQuery для доступа к методу 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);        
      });
    }
  };
});

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


Примечание. Функции можно делегировать директивам с помощью выделенных областей {fun: '&'}, что стоит посмотреть, но это увеличивает сложность.

Ответ 2

Работая с 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, так как я извлек его из более сложного приложения.

Ответ 3

Начиная с вышеперечисленных делегатов BradGreens, я адаптировал некоторый код из 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);
        });
    };
});