AngularJS ng-click stopPropagation


433

ฉันได้คลิกกิจกรรมบนแถวของตารางและในแถวนี้ยังมีปุ่มลบพร้อมคลิกกิจกรรม เมื่อฉันคลิกที่ปุ่มลบการคลิกที่เหตุการณ์ในแถวนั้นจะเริ่มขึ้น

นี่คือรหัสของฉัน

<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เหตุการณ์ถูกไล่ออกเมื่อฉันคลิกปุ่มลบในเซลล์ตารางได้อย่างไร

คำตอบ:


801

คำสั่ง ngClick (รวมถึงคำสั่งเหตุการณ์อื่น ๆ ทั้งหมด) สร้าง$eventตัวแปรที่มีอยู่ในขอบเขตเดียวกัน ตัวแปรนี้เป็นการอ้างอิงถึงeventวัตถุJS และสามารถใช้โทรได้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


2
ฉันไม่สามารถคิดออกได้ว่านี่มีอยู่ในรหัสคอนโทรลเลอร์หรือไม่ - $ scope $ เหตุการณ์ดูเหมือนจะไม่ทำงาน ความคิดใด ๆ
user1338062

93
@ วัตถุเหตุการณ์ถูกสร้างขึ้นภายในคำสั่ง ng-click และคุณสามารถส่งต่อไปยังng-clickฟังก์ชันตัวจัดการของคุณng-click="deleteUser(user.id, $event)"ได้
Stewie

6
ขอบคุณชนิดของการคิดว่า แต่ฉันคิดว่ามันยังคงเหม็น :)
user1338062

2
ฉันคิดว่ามันเป็นปฏิปักษ์ต่อการดำเนินการหลายแสดงออกเช่นนี้ ทำไมไม่เพียงแค่ส่งเหตุการณ์ $ เป็นอาร์กิวเมนต์ที่สามไปยัง deleteUser () จากนั้น stopPropagation () ภายในฟังก์ชันนั้น
djheru

18
ฉันต้องเพิ่ม$event.preventDefault()ด้วยมิฉะนั้นการโทร$event.stopPropagation()จะเป็นการพาฉันไปที่รูทของแอพเมื่อคลิกปุ่ม
Desty

124

นอกเหนือจากคำตอบของสตีวี ในกรณีที่การติดต่อกลับของคุณตัดสินใจว่าการแพร่กระจายควรหยุดหรือไม่ฉันพบว่ามีประโยชน์ในการส่งผ่าน$eventวัตถุไปยังการเรียกกลับ:

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

จากนั้นในการติดต่อกลับคุณสามารถตัดสินใจได้ว่าการแพร่กระจายของเหตุการณ์จะหยุดลงหรือไม่:

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

10
สิ่งนี้จะสวยงามกว่าเรียกใช้นิพจน์หลายรายการในแอตทริบิวต์ html ขอบคุณ
Eason

3
อย่าลืมใส่อาร์กิวเมนต์ '$ event' ไว้ในคำสั่ง html ng-click ฉันสะดุดในตอนแรก
ThinkBonobo

1
สำหรับการหยุดทันทีดีกว่าใช้ $ event.stopImmediatePropagation ()
Edgar Chavolla

เรียบง่าย แต่ก็เพิกเฉย ฉันกำลังดูคำตอบที่เลือกและคิดว่า "จริงเหรอนี้น่าเกลียด?" ไม่ได้ตระหนักถึงผ่านมันเป็นพารามิเตอร์ ดีจริงๆ.
tfrascaroli

10

ฉันเขียนคำสั่งที่ให้คุณ จำกัด พื้นที่ที่การคลิกมีผล มันสามารถใช้สำหรับบางสถานการณ์เช่นนี้ได้ดังนั้นแทนที่จะต้องจัดการกับการคลิกเป็นกรณี ๆ ไปคุณสามารถพูดว่า "การคลิกจะไม่ออกมาจากองค์ประกอบนี้"

คุณจะใช้มันแบบนี้:

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

ดี! ฉันเปลี่ยนชื่อคำสั่งของคุณngClickเป็นเพราะฉันไม่ต้องการเผยแพร่เหตุการณ์ที่จัดการแล้ว
maaartinus

1
ระวังให้ดี ปลั๊กอินอื่น ๆ อาจต้องการฟังการคลิกเหล่านั้น หากคุณใช้เคล็ดลับเครื่องมือที่ปิดเมื่อคลิกที่อยู่ด้านนอกพวกเขาอาจไม่ปิดเพราะการคลิกภายนอกจะไม่แพร่กระจายไปยังเนื้อหา
เจนส์

นั่นเป็นประเด็นที่ดี แต่ปัญหานี้จะเกิดขึ้นกับคำสั่งของคุณด้วย บางทีฉันควรเพิ่มสถานที่เช่นignoreNgClick=trueกิจกรรมและจัดการกับมัน ... อย่างใด เป็นการดีที่ในngClickคำสั่งดั้งเดิมแต่การปรับเปลี่ยนมันฟังดูสกปรก
maaartinus

ใช่มันเป็นเพราะเหตุใดฉันจึงไม่ใช้คำสั่งนี้เว้นแต่ฉันต้องการมันจริงๆ เมื่อฉันต้องทำให้คำสั่งอื่นเพื่อดำเนินการเผยแพร่คลิกต่อเนื่องจากเหตุผลอย่างนี้ ดังนั้นฉันจึงมีคำสั่งแบบแยกคลิกแล้วผู้ปกครองคู่ขึ้นฉันมีคำสั่งคลิกอย่างต่อเนื่องอื่น วิธีนี้ทำให้การคลิกถูกข้ามไปสำหรับองค์ประกอบกลางเท่านั้น
เจนส์

1

ในกรณีที่คุณกำลังใช้คำสั่งแบบฉันนี่เป็นวิธีการทำงานเมื่อคุณต้องการผูกข้อมูลทั้งสองวิธีหลังจากอัปเดตแอตทริบิวต์ในรูปแบบหรือคอลเลกชันใด ๆ :

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

ตอนนี้คุณสามารถใช้งานได้อย่างง่ายดายในปุ่มลิงก์ลิ้งค์และอื่น ๆ เช่น:

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

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


7
คุณจะเพิ่มคำอธิบายว่าทำไมคุณถึงคิดว่าสิ่งนี้ตอบคำถามได้หรือไม่
paisanco

มันเป็นคำตอบของคำถาม มันแสดงให้เห็นวิธีการส่งผ่านในเหตุการณ์ไปยังการเรียกกลับซึ่งเป็นมากกว่าคำถามเริ่มต้นคิดออก
ศิลา
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.