AngularJS ng-klik stopPropagation

433

Saya memiliki klik Acara di baris tabel dan di baris ini ada juga Tombol hapus dengan klik Acara. Ketika saya mengklik tombol hapus, klik Acara di baris juga diaktifkan.

Ini kode saya.

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

Bagaimana saya bisa mencegah bahwa showUserAcara dipecat ketika saya mengklik Tombol hapus di sel tabel?

michael_knight
sumber

Jawaban:

801

arahan ngClick (dan juga semua arahan acara lainnya) menciptakan $eventvariabel yang tersedia pada cakupan yang sama. Variabel ini adalah referensi ke eventobjek JS dan dapat digunakan untuk memanggil 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

Stewie
sumber
2
Saya tidak tahu apakah ini tersedia dalam kode controller - $ scope. $ Event sepertinya tidak berfungsi. Ada ide?
user1338062
93
objek @event dibuat dalam ng-klik direktif, dan tersedia untuk Anda untuk menyebarkannya ke Anda ng-clickfungsi handler: ng-click="deleteUser(user.id, $event)".
Stewie
6
Terima kasih, agak mengira itu, tapi saya pikir itu masih bau :)
user1338062
2
Saya pikir ini adalah antipattern untuk mengeksekusi banyak ekspresi seperti ini. Mengapa tidak hanya meneruskan $ event sebagai argumen ketiga untuk deleteUser () dan kemudian stopPropagation () di dalam fungsi itu?
djheru
18
Saya harus menambahkan $event.preventDefault()juga, jika tidak menelepon berarti $event.stopPropagation()mengarahkan saya ke root aplikasi saya ketika mengklik tombol.
Desty
124

Tambahan untuk jawaban Stewie. Jika callback Anda memutuskan apakah propagasi harus dihentikan atau tidak, saya merasa berguna untuk meneruskan $eventobjek ke callback:

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

Dan kemudian di dalam callback itu sendiri, Anda dapat memutuskan apakah propagasi acara harus dihentikan:

$scope.childHandler = function ($event) {
  if (wanna_stop_it()) {
    $event.stopPropagation();
  }
  ...
};
korya
sumber
10
ini lebih elegan daripada mengeksekusi banyak ekspresi dalam atribut html, terima kasih
Eason
3
Ingatlah untuk menempatkan argumen '$ event', di arahan html ng-klik. Saya tersandung pada awalnya.
ThinkBonobo
1
Untuk pemberhentian langsung lebih baik gunakan $ event.stopImmediatePropagation ()
Edgar Chavolla
Sangat sederhana, namun begitu diabaikan. Saya melihat jawaban yang dipilih dan berpikir "benarkah? INI jelek?". Bahkan tidak menyadari untuk meneruskannya sebagai parameter. Benar-benar bagus.
tfrascaroli
10

Saya menulis arahan yang memungkinkan Anda membatasi area di mana klik berpengaruh. Ini dapat digunakan untuk skenario tertentu seperti ini, jadi daripada harus berurusan dengan klik pada kasus per kasus, Anda bisa mengatakan "klik tidak akan keluar dari elemen ini".

Anda akan menggunakannya seperti ini:

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

Perlu diingat bahwa ini akan mencegah semua klik pada sel terakhir, bukan hanya tombol. Jika bukan itu yang Anda inginkan, Anda mungkin ingin membungkus tombol seperti ini:

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

Ini adalah kode arahannya:

angular.module('awesome', []).directive('isolateClick', function() {
    return {
        link: function(scope, elem) {
            elem.on('click', function(e){
                e.stopPropagation();
            });
        }
   };
});
Jens
sumber
Bagus! Saya telah mengubah nama arahan Anda ngClick, karena saya sebenarnya tidak pernah ingin menyebarkan acara yang sudah ditangani.
maaartinus
1
Hati-hati dengan itu. Beberapa plugin lain mungkin benar-benar ingin mendengarkan klik itu. Jika Anda menggunakan tooltips yang menutup ketika mengklik di luar mereka mungkin tidak pernah ditutup, karena klik luar tidak disebarkan ke tubuh.
Jens
Itu poin yang bagus, tetapi masalah ini akan terjadi dengan arahan Anda juga. Mungkin saya harus menambahkan properti seperti ignoreNgClick=trueke acara dan menanganinya ... entah bagaimana. Idealnya, dalam ngClickarahan asli , tetapi memodifikasi itu terdengar kotor.
maaartinus
Ya, itu sebabnya saya tidak akan menggunakan arahan ini kecuali saya benar-benar membutuhkannya. Suatu kali saya bahkan harus membuat arahan lain untuk melanjutkan propagasi klik karena alasan ini. Jadi saya memiliki arahan klik-terisolasi, lalu beberapa orang tua saya memiliki arahan klik-lanjut yang lain. Dengan cara ini klik hanya dilewati untuk elemen tengah.
Jens
1

Jika Anda menggunakan arahan seperti saya, ini adalah cara kerjanya ketika Anda membutuhkan dua cara pengikatan data misalnya setelah memperbarui atribut dalam model atau koleksi apa pun:

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

Sekarang, Anda dapat dengan mudah menggunakannya di sembarang tombol, tautan, div, dll. Seperti:

<button set-survey-in-edition-mode >Edit survey</button>
heriberto perez
sumber
-14
<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;
      }
   };

Kelihatannya
sumber
7
Akankah Anda menambahkan penjelasan mengapa menurut Anda ini menjawab pertanyaan?
paisanco
Ini semacam menjawab pertanyaan. Ini menunjukkan bagaimana untuk lulus dalam acara tersebut ke callback yang merupakan lebih dari apa pertanyaan awal dijawab.
hewstone