AngularJS ng-click stopPropagation


433

Tôi có một nhấp chuột Sự kiện trên một hàng của bảng và trong hàng này cũng có một nút xóa với một sự kiện nhấp chuột. Khi tôi nhấp vào nút xóa, nhấp vào Sự kiện trên hàng cũng được kích hoạt.

Đây là mã của tôi.

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

Làm cách nào để ngăn showUsersự kiện được kích hoạt khi tôi nhấp vào nút xóa trong ô của bảng?

Câu trả lời:


801

Chỉ thị ngClick (cũng như tất cả các chỉ thị sự kiện khác) tạo ra $eventbiến có sẵn trên cùng một phạm vi. Biến này là một tham chiếu đến eventđối tượng JS và có thể được sử dụng để gọi 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
Tôi không thể tìm ra nếu điều này có sẵn trong mã điều khiển - $ scope. $ Event dường như không hoạt động. Có ý kiến ​​gì không?
user1338062

93
Đối tượng @event được tạo bên trong chỉ thị ng-click và nó có sẵn để bạn chuyển nó sang ng-clickchức năng xử lý của bạn : ng-click="deleteUser(user.id, $event)".
Stewie

6
Cảm ơn, loại đã tìm ra cái đó, nhưng tôi nghĩ nó vẫn còn hôi thối :)
user1338062

2
Tôi nghĩ rằng đó là một phản mẫu để thực hiện nhiều biểu thức như thế này. Tại sao không chỉ truyền $ event làm đối số thứ ba để xóaUser () và sau đó stopPropagation () bên trong hàm đó?
djheru

18
Tôi cũng phải thêm $event.preventDefault(), nếu không, cuộc gọi $event.stopPropagation()đã chuyển hướng tôi đến thư mục gốc của ứng dụng khi nhấp vào nút.
Desty

124

Một bổ sung cho câu trả lời của Stewie. Trong trường hợp khi cuộc gọi lại của bạn quyết định liệu việc truyền có nên dừng lại hay không, tôi thấy việc truyền $eventđối tượng cho cuộc gọi lại là hữu ích :

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

Và sau đó trong chính cuộc gọi lại, bạn có thể quyết định liệu việc truyền bá sự kiện có nên được dừng lại hay không:

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

10
Điều này thanh lịch hơn là thực thi nhiều biểu thức trong thuộc tính html, cảm ơn
Eason

3
Hãy nhớ đặt đối số '$ event', trong chỉ thị nhấp chuột html. Tôi đã vấp phải điều đó lúc đầu.
ThinkBonobo

1
Để dừng ngay lập tức, hãy sử dụng $ event.stopImmediatePropagation ()
Edgar Chavolla 30/03/2016

Vì vậy, đơn giản, nhưng bỏ qua. Tôi đã nhìn vào câu trả lời được chọn và nghĩ "thật sao? NÀY xấu xí?". Thậm chí không nhận ra để vượt qua nó như là một tham số. Thực sự tốt đẹp.
tfrascaroli

10

Tôi đã viết một chỉ thị cho phép bạn giới hạn các khu vực nơi một nhấp chuột có hiệu lực. Nó có thể được sử dụng cho một số trường hợp nhất định như kịch bản này, vì vậy thay vì phải xử lý nhấp chuột theo từng trường hợp, bạn chỉ có thể nói "nhấp chuột sẽ không xuất phát từ yếu tố này".

Bạn sẽ sử dụng nó như thế này:

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

Hãy nhớ rằng điều này sẽ ngăn tất cả các nhấp chuột vào ô cuối cùng, không chỉ nút. Nếu đó không phải là những gì bạn muốn, bạn có thể muốn quấn nút như thế này:

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

Đây là mã của lệnh:

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

Đẹp! Tôi đã đổi tên chỉ thị của bạn thành ngClick, vì tôi thực sự không bao giờ muốn tuyên truyền một sự kiện đã được xử lý.
maaartinus

1
Hãy cẩn thận với điều đó. Một số plugin khác thực sự có thể muốn nghe những nhấp chuột đó. Nếu bạn sử dụng các chú giải công cụ đóng khi nhấp vào bên ngoài, chúng có thể không bao giờ đóng, vì các nhấp chuột bên ngoài không được truyền vào cơ thể.
Jens

Đó là một điểm tốt, nhưng vấn đề này cũng sẽ xảy ra với chỉ thị của bạn. Có lẽ tôi chỉ nên thêm một tài sản như ignoreNgClick=truesự kiện và xử lý nó ... bằng cách nào đó. Lý tưởng nhất là trong ngClickchỉ thị ban đầu , nhưng sửa đổi nó nghe có vẻ bẩn.
maaartinus

Đúng vậy, đó là lý do tại sao tôi không sử dụng chỉ thị này trừ khi tôi thực sự cần nó. Có lần tôi thậm chí đã phải thực hiện một chỉ thị khác để tiếp tục tuyên truyền nhấp chuột vì lý do này. Vì vậy, tôi đã có một chỉ thị nhấp chuột cô lập, sau đó một cặp cha mẹ lên tôi đã có một chỉ thị nhấp chuột tiếp tục. Bằng cách này, nhấp chuột chỉ được bỏ qua cho các yếu tố giữa.
Jens

1

Trong trường hợp bạn đang sử dụng một lệnh như tôi thì đây là cách nó hoạt động khi bạn cần ràng buộc hai cách dữ liệu sau khi cập nhật một thuộc tính trong bất kỳ mô hình hoặc bộ sưu tập nào:

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

Bây giờ, bạn có thể dễ dàng sử dụng nó trong bất kỳ nút, liên kết, div, v.v.

<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
Bạn có thể thêm một số giải thích về lý do tại sao bạn nghĩ rằng điều này trả lời câu hỏi?
paisanco

Nó loại câu trả lời cho câu hỏi. Nó cho thấy làm thế nào để chuyển trong sự kiện đến cuộc gọi lại, nhiều hơn những gì câu hỏi ban đầu đã tìm ra.
hewstone
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.