Apa cara terbaik untuk membatalkan propagasi acara antara panggilan ng-klik bersarang?

180

Ini sebuah contoh. Katakanlah saya ingin memiliki hamparan gambar seperti banyak situs. Jadi ketika Anda mengklik thumbnail, overlay hitam muncul di seluruh jendela Anda, dan versi gambar yang lebih besar berada di tengahnya. Mengklik overlay hitam mengabaikannya; mengklik gambar akan memanggil fungsi yang menampilkan gambar berikutnya.

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

Masalahnya adalah bahwa dengan pengaturan ini, jika Anda mengklik gambar, keduanya nextImage()dan hideOverlay()dipanggil. Tetapi yang saya inginkan hanyalah nextImage()dipanggil.

Saya tahu Anda dapat menangkap dan membatalkan acara dalam nextImage()fungsi seperti ini:

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

... Tapi saya ingin tahu apakah ada cara AngularJS yang lebih baik untuk melakukannya yang tidak mengharuskan saya untuk awalan semua fungsi pada elemen di dalam overlay dengan cuplikan ini.

Cilphex
sumber
1
return falsedi akhir acara
Jonathan de M.
1
Saya percaya itulah cara melakukannya onclick, bukan ng-click.
Michael Scheper

Jawaban:

193

Apa yang dikatakan @JosephSilber, atau meneruskan objek $ event ke dalam ng-clickcallback dan menghentikan propagasi di dalamnya:

<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
}
Stewie
sumber
8
gunakan $ event.preventDefault (); dalam v> 1,5
KoolKabin
3
@KoolKabin Saya menggunakan Angular 1.5.8 dan $ event.stopPropagation () masih berfungsi dengan baik. $ event.preventDefault () tidak berfungsi
HammerNL
1
Aneh, karena saya memiliki situasi yang berlawanan. stopPropagation tidak berfungsi lagi, tetapi mencegahDefault () tidak. Satu-satunya perbedaan adalah bahwa saya dipanggil langsung pada ng-klik. <tr ng-klik = "ctr.foo (); $ event.preventDefault ()"> ..... </tr>
MilitelloVinx
171

Gunakan $event.stopPropagation():

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

Berikut ini demo: http://plnkr.co/edit/3Pp3NFbGxy30srl8OBmQ?p=preview

Joseph Silber
sumber
Saya masuk ReferenceError: $event is not definedkonsol.
cilphex
Ya, itu tidak ... itu juga berfungsi ketika saya menulis versi sederhana yang terpisah dari awal. Saya mencoba mencari tahu apa yang bisa membuatnya tidak berfungsi dalam kode pengembangan saya. Tak tahu: \
cilphex
@cilphex - Apakah Anda menggunakan versi Angular yang terbaru?
Joseph Silber
Ya - baru menemukan masalahnya. Saat pengujian saya mencoba meletakkan $event.stopPropagation()di tempat yang tidak berfungsi. Lupa menghapusnya. Jadi, bahkan ketika saya meletakkannya di tempat yang benar-benar berfungsi, itu disebut untuk yang kedua kalinya. Menyingkirkan duplikat yang disfungsional dan berhasil. Terima kasih atas bantuan Anda.
cilphex
101

Saya suka ide menggunakan arahan untuk ini:

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

Kemudian gunakan direktif seperti:

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

Jika Anda mau, Anda bisa menjadikan solusi ini lebih umum seperti jawaban ini untuk pertanyaan yang berbeda: https://stackoverflow.com/a/14547223/347216

David Ipsen
sumber
2
Jika elemen Anda ditambahkan / dihapus dari DOM secara dinamis, jangan lupa perhatikan elemen Anda untuk acara '$ destroy' sehingga Anda dapat melepaskan ikatan handler. Misalnya, element.on ('$ destroy', function () {/ * lakukan unbinding di sini * /});
broc.seib
itu stop-eventatribut html? Saya tidak dapat menemukannya di Jaringan Pengembang Mozilla atau di mana pun.
Ehtesh Choudhury
3
@EhteshChoudhury - "stop-event" adalah arahan baru yang saya buat di cuplikan JS di atas. Lihat lebih lanjut tentang mendeklarasikan dan menggunakan arahan di sini: docs.angularjs.org/guide/directive
David Ipsen
Solusi bagus! Saya benar-benar mendaftarkan angular-eat-eventarahan pada bower, yang bekerja dengan cara yang sama!
gion_13
sepertinya tidak berfungsi, ng-klik mengevaluasi sebelum arahan. jadi saya bisa mencegah arahan dari mengeksekusi tetapi tidak sebaliknya.
Rafael
31

Terkadang, mungkin paling masuk akal untuk melakukan ini:

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

Saya memilih untuk melakukannya dengan cara ini karena saya tidak ingin myClickHandler()menghentikan penyebaran acara di banyak tempat lain yang digunakan.

Tentu, saya bisa menambahkan parameter boolean ke fungsi handler, tetapi stopPropagation()jauh lebih bermakna dari sekedar true.

Michael Scheper
sumber
2
Saya selalu menyukai versi ini, sepertinya elemen bersarang tidak boleh terkait dengan fungsi yang saya panggil
mcfedr
Saya harus menambahkan $event.stopPropagation()elemen internal.
Kishor Pawar
@KishorPawar: Kenapa? Apakah cara saya melakukannya dalam jawaban tidak berhasil untuk Anda? Jika tidak, sebaiknya kita mencari tahu apakah itu karena perubahan cara kerja Angular, atau masalah dalam kode Anda.
Michael Scheper
@MichaelScheper Saya telah checkboxdibungkus divelemen. Saya divmengambil 12 kolom dan checkboxmengatakan 3 kolom. Saya ingin memanggil fungsi Apada klik divdan fungsi Bpada klik checkbox. jadi ketika saya mengklik checkboxkedua fungsi itu dipanggil. Ketika saya menambahkan ng-click="$event.stopPropagation()"ke checkbox, aku hanya fungsi Bdipanggil.
Kishor Pawar
@KishorPawar: Ah. Ya, saya akan mengharapkan ini, dan memang, intinya stopPropagation()adalah menghentikan acara yang menyebar ke elemen induk. Saya tidak yakin bagaimana Anda menyebutnya Bkarena itu tidak ditetapkan dalam ng-click, tapi titik jawabannya adalah bahwa Anda dapat melakukan ini: <checkbox ng-click="B(); $event.stopPropagation()">. Anda tidak harus memasukkan stopPropagation()fungsi ke dalam B.
Michael Scheper
7

Ini bekerja untuk saya:

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

this.doSomething = function($event) {
  $event.stopPropagation();
  $event.preventDefault();
};
Andrey Shatilov
sumber
Saya ingin menangani klik mouse dengan atau tanpa menekan tombol Ctrl. Untuk menghentikan pemilihan (dan sorot) elemen HTML di browser (IE 11 dalam kasus saya) ketika pengguna mengklik berbagai item dengan menahan tombol Ctrl, saya harus menggunakan acara ng-mousedown dan membatalkan perilaku default melalui $ event .preventDefault ()
pholpar
4

Jika Anda tidak ingin harus menambahkan berhenti propagasi ke semua tautan ini berfungsi juga. Sedikit lebih scalable.

$scope.hideOverlay( $event ){

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

}
Hampus Ahlgren
sumber
2
Solusi ini berfungsi untuk contoh yang diberikan (yang hebat!), Namun itu tidak berfungsi ketika div luar memiliki n atau lebih elemen bersarang sebelum klik href / ng-klik. Kemudian ketika callback hideOverlay () dipanggil target adalah salah satu elemen bersarang dan bukan elemen terluar dengan arahan ng-klik. Untuk menangani elemen bersarang, orang bisa menggunakan jquery untuk mendapatkan orang tua dan melihat apakah orang tua yang dapat diklik (a, ng-klik, dll.) Memiliki kelas overlay, tetapi itu terlihat agak rumit ...
Amir
console.log ("potatooverlay" .indexOf ("overlay")! = -1); console.log (/ \ boverlay \ b / g.test ("potatooverlay"));
sudut akan membiarkan Anda melakukannya event.target.classList.indexOf('overlay') Dan trik itu berfungsi dengan baik bahkan ketika div bersarang di div lain
deltree
0

Jika Anda memasukkan ng-klik = "$ event.stopPropagation" pada elemen induk dari templat Anda, stopPropogation akan ketahuan saat gelembung naik ke pohon, jadi Anda hanya perlu menulisnya sekali untuk seluruh templat Anda.

cabang
sumber
0

Anda dapat mendaftarkan arahan lain di atas ng-clickyang mengubah perilaku default ng-clickdan menghentikan propagasi acara. Dengan cara ini Anda tidak perlu menambahkan $event.stopPropagationdengan tangan.

app.directive('ngClick', function() {
    return {
        restrict: 'A',
        compile: function($element, attr) {
            return function(scope, element, attr) {
                element.on('click', function(event) {
                    event.stopPropagation();
                });
            };
        }
    }
});
bert
sumber
0
<div ng-click="methodName(event)"></div>

DI pengontrol digunakan

$scope.methodName = function(event) { 
    event.stopPropagation();
}
Dinesh Jain
sumber
Kirim acara pertama dalam metode untuk melakukannya
Dinesh Jain
Jawaban Anda tidak menambah apa pun yang diterima 4 tahun yang lalu
Ilya Luzyanin