web-dev-qa-db-fra.com

AngularJS ng-click stopPropagation

J'ai un événement de clic sur une ligne de la table et dans cette ligne se trouve également un bouton de suppression avec un événement de clic. Lorsque je clique sur le bouton de suppression, l'événement de clic sur la ligne est également déclenché.

Voici mon code.

<tbody>
  <tr ng-repeat="user in users" class="repeat-animation" ng-click="showUser(user, $index)">
    <td>{{user.firstname}}</td>
    <td>{{user.lastname}}</td>
    <td>{{user.email}}</td>
    <td><button class="btn red btn-sm" ng-click="deleteUser(user.id, $index)">Delete</button></td>
  </tr>
</tbody>

Comment puis-je empêcher que l'événement showUser soit déclenché lorsque je clique sur le bouton de suppression dans la cellule du tableau?

420
michael_knight

la directive ngClick (ainsi que toutes les autres directives sur les événements) crée la variable $event qui est disponible sur la même étendue. Cette variable est une référence à l'objet JS event et peut être utilisée pour appeler stopPropagation():

<table>
  <tr ng-repeat="user in users" ng-click="showUser(user)">
    <td>{{user.firstname}}</td>
    <td>{{user.lastname}}</td>
    <td>
      <button class="btn" ng-click="deleteUser(user.id, $index); $event.stopPropagation();">
        Delete
      </button>
    </td>              
  </tr>
</table>

PLUNKER

778
Stewie

Un ajout à la réponse de Stewie. Dans le cas où votre rappel décide si la propagation doit être arrêtée ou non, il m'a été utile de transmettre l'objet $event au rappel:

<div ng-click="parentHandler($event)">
  <div ng-click="childHandler($event)">
  </div>
</div>

Et ensuite, dans le rappel lui-même, vous pouvez décider si la propagation de l'événement doit être stoppée:

$scope.childHandler = function ($event) {
  if (wanna_stop_it()) {
    $event.stopPropagation();
  }
  ...
};
122
korya

J'ai écrit une directive qui vous permet de limiter les zones où un clic a un effet. Il pourrait être utilisé pour certains scénarios tels que celui-ci. Par conséquent, au lieu d'avoir à gérer le clic au cas par cas, vous pouvez simplement dire "les clics ne sortiront pas de cet élément".

Vous l'utiliseriez comme ceci:

<table>
  <tr ng-repeat="user in users" ng-click="showUser(user)">
    <td>{{user.firstname}}</td>
    <td>{{user.lastname}}</td>
    <td isolate-click>
      <button class="btn" ng-click="deleteUser(user.id, $index);">
        Delete
      </button>
    </td>              
  </tr>
</table>

Gardez à l'esprit que cela empêcherait tous les clics sur la dernière cellule, pas seulement le bouton. Si ce n'est pas ce que vous voulez, vous voudrez peut-être envelopper le bouton comme ceci:

<span isolate-click>
    <button class="btn" ng-click="deleteUser(user.id, $index);">
        Delete
    </button>
</span>

Voici le code de la directive:

angular.module('awesome', []).directive('isolateClick', function() {
    return {
        link: function(scope, elem) {
            elem.on('click', function(e){
                e.stopPropagation();
            });
        }
   };
});
10
Jens

Dans le cas où vous utilisez une directive comme moi, voici comment cela fonctionne lorsque vous avez besoin de la liaison de type données, par exemple après la mise à jour d'un attribut dans un modèle ou une collection:

angular.module('yourApp').directive('setSurveyInEditionMode', setSurveyInEditionMode)

function setSurveyInEditionMode() {
  return {
    restrict: 'A',
    link: function(scope, element, $attributes) {
      element.on('click', function(event){
        event.stopPropagation();
        // In order to work with stopPropagation and two data way binding
        // if you don't use scope.$apply in my case the model is not updated in the view when I click on the element that has my directive
        scope.$apply(function () {
          scope.mySurvey.inEditionMode = true;
          console.log('inside the directive')
        });
      });
    }
  }
}

Maintenant, vous pouvez facilement l'utiliser dans n'importe quel bouton, lien, div, etc., comme ceci:

<button set-survey-in-edition-mode >Edit survey</button>
1
heriberto perez