ネストされたng-click呼び出し間のイベント伝播をキャンセルする最良の方法は何ですか?


180

ここに例があります。多くのサイトのようにイメージオーバーレイを作成したいとします。したがって、サムネイルをクリックすると、ウィンドウ全体に黒いオーバーレイが表示され、画像の拡大版が中央に表示されます。黒いオーバーレイをクリックすると、表示が消えます。画像をクリックすると、次の画像を表示する関数が呼び出されます。

HTML:

<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
    <img src="http://some_src" ng-click="nextImage()"/>
</div>

JavaScript:

function OverlayCtrl($scope) {
    $scope.hideOverlay = function() {
        // Some code to hdie the overlay
    }
    $scope.nextImage = function() {
        // Some code to find and display the next image
    }
}

あなたは画像をクリックして、両方の場合、問題は、この設定でそれであるnextImage()hideOverlay()呼ばれています。しかし、私が欲しいのは、nextImage()呼ばれることだけです。

次のnextImage()ような関数でイベントをキャプチャしてキャンセルできることを知っています。

if (window.event) {
    window.event.stopPropagation();
}

...しかし、オーバーレイ内の要素のすべての関数にこのスニペットをプレフィックスする必要がない、より優れたAngularJSの方法があるかどうかを知りたいです。


1
return false関数の最後
ジョナサンドM.

1
それがのためonclickではなく、のための方法だと思いますng-click
Michael Scheper、2015年

回答:


193

@JosephSilberの発言、または$ eventオブジェクトをng-clickコールバックに渡し、その中の伝播を停止します。

<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
  <img src="http://some_src" ng-click="nextImage($event)"/>
</div>
$scope.nextImage = function($event) {
  $event.stopPropagation();
  // Some code to find and display the next image
}

8
$ event.preventDefault();を使用します v> 1.5
KoolKabin

3
@KoolKabin Angular 1.5.8を使用していますが、$ event.stopPropagation()は引き続き正常に機能します。$ event.preventDefault()は機能しません
HammerNL

1
奇妙なことに、私は反対の状況にいます。stopPropagationは機能しなくなりましたが、preventDefault()は機能します。唯一の違いは、ng-clickで直接呼び出したことです。<tr ng-click = "ctr.foo(); $ event.preventDefault()"> ..... </ tr>
MilitelloVinx

171

使用$event.stopPropagation()

<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
    <img src="http://some_src" ng-click="nextImage(); $event.stopPropagation()" />
</div>

ここにデモがあります:http : //plnkr.co/edit/3Pp3NFbGxy30srl8OBmQ?p=preview


私が手ReferenceError: $event is not definedコンソールで。
cilphex 2013年

はい、動作します...別のシンプルなバージョンを最初から作成するときにも機能します。開発コードで機能しない原因を突き止めようとしています。
Dunno

@cilphex-Angularの最新バージョンを使用していますか?
ジョセフSilber

はい-問題が見つかりました。テストするとき$event.stopPropagation()、動かない場所に置いてみました。削除するのを忘れました。ですから、それが機能する場所に置いたとしても、機能しない場所でもう一度呼び出されていました。機能不全の重複を取り除き、成功しました。ご協力いただきありがとうございます。
cilphex 2013年

101

私はこれにディレクティブを使用するアイデアが好きです:

.directive('stopEvent', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            element.bind('click', function (e) {
                e.stopPropagation();
            });
        }
    };
 });

次に、次のようなディレクティブを使用します。

<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
    <img src="http://some_src" ng-click="nextImage()" stop-event/>
</div>

必要に応じて、別の質問に対するこの回答のように、このソリューションをより一般的にすることができます:https : //stackoverflow.com/a/14547223/347216


2
要素がDOMから動的に追加または削除される場合は、ハンドラーのバインドを解除できるように、 '$ destroy'イベントの要素を監視することを忘れないでください。たとえば、element.on( '$ destroy'、function(){/ *ここでバインドを解除します* /});
broc.seib 2014

あるstop-eventHTML属性は?Mozilla Developer Networkや他の場所では見つかりませんでした。
Ehtesh Choudhury 2014

3
@EhteshChoudhury-「stop-event」は、上記のJSスニペットで作成した新しいディレクティブです。ディレクティブの宣言と使用の詳細については、こちらをご覧ください:docs.angularjs.org/guide/directive
David Ipsen

素敵な解決策!私は実際angular-eat-eventにバウワーにディレクティブを登録しましたが、これは同じように機能します!
gion_13 2015

動作しないようです。ng-clickはディレクティブの前に評価されます。ディレクティブの実行を防ぐことができますが、その逆はできません。
ラファエル

31

時々、これを行うだけで最も理にかなうことがあります。

<widget ng-click="myClickHandler(); $event.stopPropagation()"/>

myClickHandler()他の多くの場所でイベントの伝播を止めたくなかったので、この方法を選択しました。

確かに、ハンドラー関数にブール値のパラメーターを追加することもできますが、stopPropagation()それだけではありませんtrue


2
私はいつもこのバージョンが好きでした、要素の入れ子は私が呼んでいる関数と関係があるべきではないようです
mcfedr

$event.stopPropagation()内部要素に追加する必要がありました。
Kishor Pawar 2017

@KishorPawar:なぜ?答えで私がした方法はあなたにとってうまくいきませんでしたか?そうでない場合は、Angularの動作方法が変更されたためか、コードに問題があるためかを調べるのに役立ちます。
Michael Scheper 2017

@MichaelScheper 要素でcheckboxラップしていdivます。私divは12列、checkbox3列としています。私は、関数を呼び出すために望んでいたAのをクリック上div及び機能Bのクリックでcheckbox。クリックするとcheckbox両方の関数が呼び出されていました。に追加するng-click="$event.stopPropagation()"checkbox、関数のみがB呼び出されます。
キショールパワル2017

@KishorPawar:ああ。はい、私はこれを期待します。実際のポイントはstopPropagation()、親要素に伝播するイベントを停止することです。で指定されていないBため、どのように呼び出すのかはわかりませんng-clickが、答えの要点は次のようにできることです<checkbox ng-click="B(); $event.stopPropagation()">stopPropagation()関数をに含める必要はありませんB
Michael Scheper 2017

7

これは私にとってはうまくいきます:

<a href="" ng-click="doSomething($event)">Action</a>

this.doSomething = function($event) {
  $event.stopPropagation();
  $event.preventDefault();
};

Ctrlキーを押すかどうかに関係なく、マウスクリックを処理したいと思いました。ユーザーがCtrlキーを押しながらさまざまなアイテムをクリックしたときにブラウザー(私の場合はIE 11)でHTML要素の選択を停止(および強調表示)するには、ng-mousedownイベントを使用し、$ eventを介してデフォルトの動作をキャンセルする必要がありました。 .preventDefault()
pholpar 2016

4

すべてのリンクに停止伝播を追加する必要がない場合は、これも機能します。もう少しスケーラブルです。

$scope.hideOverlay( $event ){

   // only hide the overlay if we click on the actual div
   if( $event.target.className.indexOf('overlay') ) 
      // hide overlay logic

}

2
このソリューションは提供された例(すばらしい!)で機能しますが、href / ng-clickの前に外側のdivにn個以上のネストされた要素がある場合は機能しません。次に、hideOverlay()コールバックが呼び出されると、ターゲットはネストされた要素の1つであり、ng-clickディレクティブを持つ最も外側の要素ではありません。ネストされた要素を処理するには、おそらくjqueryを使用して親を取得し、最初のクリック可能な(a、ng-clickなど)親にオーバーレイクラスがあるかどうかを確認しますが、少し面倒に見えます...
Amir

console.log( "potatooverlay" .indexOf( "overlay")!= -1); console.log(/ \ boverlay \ b / g.test( "potatooverlay"));

angularはあなたにそうさせますevent.target.classList.indexOf('overlay') そしてdivが他のdivにネストされているときでさえそのトリックはうまく働きます
deltree

0

テンプレートの親要素にng-click = "$ event.stopPropagation"を挿入した場合、stopPropogationはツリーを泡立たせるときにキャッチされるため、テンプレート全体に対して一度だけ記述するだけで済みます。


0

イベントのng-clickデフォルトの動作を修正しng-clickてイベントの伝播を停止する別のディレクティブを登録できます。この方法では$event.stopPropagation、手動で追加する必要はありません。

app.directive('ngClick', function() {
    return {
        restrict: 'A',
        compile: function($element, attr) {
            return function(scope, element, attr) {
                element.on('click', function(event) {
                    event.stopPropagation();
                });
            };
        }
    }
});

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.