web-dev-qa-db-ja.com

AngularJS ng-click stopPropagation

テーブル行にクリックイベントがあり、この行にはクリックイベントのある削除ボタンもあります。削除ボタンをクリックすると、行のクリックイベントも発生します。

これが私のコードです。

<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>

テーブルセルの削除ボタンをクリックしたときにshowUserイベントが発生するのを防ぐにはどうすればよいですか?

413
michael_knight

ngClickディレクティブ(および他のすべてのイベントディレクティブ)は、同じスコープで利用可能な$event変数を作成します。この変数はJSのeventオブジェクトへの参照であり、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

771
Stewie

Stewieの答えに追加。あなたのコールバックが伝播を止めるべきかどうかを決定するとき、私はそれがコールバックに$eventオブジェクトを渡すことが有用であるとわかりました:

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

そして、コールバック自体で、イベントの伝播を止めるべきかどうかを決めることができます。

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

私はあなたがクリックが効果を及ぼす領域を制限することを可能にする指令を書きました。これは、このような特定のシナリオで使用される可能性があるため、ケースバイケースでクリックを処理する必要はなく、単に「クリックはこの要素から発生しない」と言うことができます。

あなたはこのようにそれを使うでしょう:

<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>

ボタンだけでなく、最後のセルに対するすべてのクリックが防止されることに注意してください。それがあなたが望まないものであるならば、あなたはこのようにボタンを包むことを望むかもしれません:

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

これがディレクティブのコードです。

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

あなたが私のようなディレクティブを使用している場合、これはあなたが双方向のデータバインディングを必要とするときにどのように動作するかです。例えば、モデルやコレクションの属性を更新した後:

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

これで、ボタン、リンク、divなどで簡単に使用できます。

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