【问题标题】:AngularJS ng-click stopPropagationAngularJS ng-click stopPropagation
【发布时间】:2023-03-31 00:47:01
【问题描述】:

我在表格行上有一个点击事件,在这一行中还有一个带有点击事件的删除按钮。当我单击删除按钮时,该行上的单击事件也会被触发。

这是我的代码。

<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 事件被触发?

【问题讨论】:

    标签: javascript angularjs angularjs-ng-click


    【解决方案1】:

    ngClick 指令(以及所有其他事件指令)创建在同一范围内可用的 $event 变量。这个变量是对JSevent对象的引用,可以用来调用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

    【讨论】:

    • 我无法确定这是否在控制器代码中可用 - $scope.$event 似乎不起作用。有什么想法吗?
    • @event 对象在 ng-click 指令中创建,您可以将其传递给您的 ng-click 处理函数:ng-click="deleteUser(user.id, $event)"
    • 谢谢,有点想出来,但我觉得还是很臭:)
    • 我认为像这样执行多个表达式是一种反模式。为什么不直接将 $event 作为第三个参数传递给 deleteUser(),然后在该函数内部 stopPropagation()?
    • 我也必须添加 $event.preventDefault(),否则在单击按钮时调用 $event.stopPropagation() 会将我重定向到应用程序的根目录。
    【解决方案2】:

    对 Stewie 的回答的补充。如果您的回调决定是否应该停止传播,我发现将 $event 对象传递给回调很有用:

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

    然后在回调本身中,你可以决定是否应该停止事件的传播:

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

    【讨论】:

    • 这比在html属性中执行多个表达式更优雅,谢谢
    • 记得将 '$event' 参数放在 html ng-click 指令中。一开始我是偶然发现的。
    • 为了立即停止,最好使用 $event.stopImmediatePropagation()
    • 如此简单,却又如此被忽视。我看着选择的答案并想“真的吗?这很难看?”。甚至没有意识到将它作为参数传递。真的很好。
    【解决方案3】:

    我编写了一个指令,可让您限制点击生效的区域。它可以用于像这样的某些场景,因此您不必逐个处理点击,您只需说“点击不会来自这个元素”。

    你会这样使用它:

    <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,因为我实际上不想传播已处理的事件。
    • 要小心。其他一些插件可能实际上想要听这些点击。如果您使用在点击外部时关闭的工具提示,它们可能永远不会关闭,因为外部点击不会传播到正文。
    • 这是一个很好的观点,但是你的指令也会出现这个问题。也许我应该在事件中添加一个像ignoreNgClick=true 这样的属性并处理它......不知何故。理想情况下,在最初的 ngClick 指令中,但修改它听起来很脏。
    • 是的,这就是为什么我不会使用这个指令,除非我真的需要它。由于这个原因,我什至不得不做出另一个指令来继续点击传播。所以我有一个isolate-click 指令,然后是一对父母,我有另一个continue-click 指令。这样,只跳过中间元素的点击。
    【解决方案4】:

    如果您使用像我这样的指令,当您需要两种数据方式绑定时,例如在更新任何模型或集合中的属性后,它就是这样工作的:

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

    现在,您可以轻松地在任何按钮、链接、div 等中使用它,如下所示:

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

    【讨论】:

      【解决方案5】:
      <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;
            }
         };
      

      【讨论】:

      • 您能否解释一下您认为这回答了问题的原因?
      • 它回答了这个问题。它显示了如何将事件传递给回调,这比最初的问题要多。
      猜你喜欢
      • 2016-10-28
      • 1970-01-01
      • 2016-11-13
      • 2018-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多