445 votes

AngularJS ng-click stopPropagation

J'ai un événement de clic sur une ligne de tableau et dans cette ligne il y a aussi 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 le showUser L'événement est déclenché lorsque je clique sur le bouton de suppression dans la cellule du tableau ?

829voto

Stewie Points 20312

La directive ngClick (ainsi que toutes les autres directives d'événements) crée des $event qui est disponible sur la même portée. Cette variable est une référence à JS event et peut être utilisé 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>

<a href="http://plnkr.co/edit/tTgu6LJkoVVahMMtHokt?p=preview">PLUNKER</a>

2 votes

Je n'ai pas pu déterminer si cela est disponible dans le code du contrôleur - $scope.$event ne semble pas fonctionner. Avez-vous une idée ?

93 votes

L'objet @event est créé à l'intérieur de la directive ng-click, et il est à votre disposition pour le passer à votre ng-click fonction de traitement : ng-click="deleteUser(user.id, $event)" .

6 votes

Merci, je m'en doutais un peu, mais je pense que ça pue quand même :)

130voto

korya Points 1926

Un complément à la réponse de Stewie. Dans le cas où votre callback décide si la propagation doit être arrêtée ou non, j'ai trouvé utile de passer l'attribut $event à la fonction de rappel :

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

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

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

10voto

Jens Points 1254

J'ai écrit une directive qui vous permet de limiter les zones où un clic a un effet. Elle pourrait être utilisée pour certains scénarios comme celui-ci. Ainsi, au lieu de devoir 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, et pas seulement le bouton. Si ce n'est pas ce que vous voulez, vous pouvez 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();
            });
        }
   };
});

1voto

heriberto perez Points 466

Si, comme moi, vous utilisez une directive, voici comment cela fonctionne lorsque vous avez besoin d'une liaison entre deux données, par exemple après avoir mis à jour 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 suit :

<button set-survey-in-edition-mode >Edit survey</button>

-14voto

Hems Points 1
<ul class="col col-double clearfix">
 <li class="col__item" ng-repeat="location in searchLocations">
   <label>
    <input type="checkbox" ng-click="onLocationSelectionClicked($event)" checklist-model="selectedAuctions.locations" checklist-value="location.code" checklist-change="auctionSelectionChanged()" id="{{location.code}}"> {{location.displayName}}
   </label>

$scope.onLocationSelectionClicked = function($event) {
      if($scope.limitSelectionCountTo &&         $scope.selectedAuctions.locations.length == $scope.limitSelectionCountTo) {
         $event.currentTarget.checked=false;
      }
   };

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X