Saltar al contenido

Delegación de eventos angular ng-click

Solución:

Parece que angular no hace delegación de eventos con repetidores. Alguien abrió un problema en github al respecto. El argumento es si realmente conduce a un mejor desempeño.

Puede haber una solución alternativa, pero requeriría jQuery. Consiste en crear una directiva especial para usar en un elemento padre y registrar al oyente en su nodo dom.

Aquí hay un ejemplo, al que se le pasa un nombre de función que se llamará cuando se hace clic en un nodo secundario, y también se le pasa un selector para ayudar a identificar qué nodos secundarios escuchar. Dado que la implementación de jquery de angular solo nos da el bind método, que se limita a registrar oyentes de eventos en el elemento real, necesitamos cargar jQuery para tener acceso a la on o delegate método.

HTML

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

La función definida se define en el controlador y espera que se le pase un índice

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

La directiva utiliza $parse para convertir una expresión en una función que se llamará desde el detector de eventos.

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


Nota: las funciones se pueden delegar a directivas mediante aislar ámbitos {fun: '&'}, que vale la pena ver, pero esto aumenta la complejidad.

Trabajando con el ejemplo de jm-aquí, escribí una versión más concisa y flexible de esta directiva. Pensé en compartir. El crédito va a jm-;)

Mi versión intenta llamar al nombre de la función como $ scope[ fn ](e, datos), o falla correctamente.

Pasa un objeto json opcional del elemento en el que se hizo clic. Esto le permite usar expresiones angulares y pasar numerosas propiedades al método que se llama.

HTML

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

Javascript

Método del controlador

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

Constructor de directivas

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

Me encantaría escuchar comentarios si alguien desea contribuir.

No probé el método handleMenu ya que lo extraje de una aplicación más compleja.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *