AngularJS:动态绑定Click in指令多次被触发

时间:2016-02-17 06:25:43

标签: javascript jquery angularjs angularjs-directive angularjs-scope

我尝试动态添加字段,并在指令的click函数中绑定link事件。但是当我添加更多字段时,似乎会多次触发。请参阅下面的示例 -



var clicks = 0;
var app = angular.module('test', []);

app.directive('control', function($compile) {
  var linker = function(scope, element, attrs) {
    element.html('<button style="background:grey;">Button ' + scope.count + '</button>');

    element.bind('click', function() {
      clicks++;
      $('#clicks').html('Clicked ' + clicks + ' times')
    });

    $compile(element.contents())(scope);
  };

  return {
    restrict: 'E',
    scope: {
      count: '@'
    },
    link: linker
  }
});

app.controller('TestController', function($scope, $compile) {
  $scope.count = 1;
  $scope.addControl = function() {
    $('#content').append('<control count="' + $scope.count+++'"></control>');
    $compile($('#content').contents())($scope);
  };
});
&#13;
#content {
  margin-top: 10px;
}
#clicks {
  margin-top: 10px;
}
p {
  color: grey;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="TestController">
  <button ng-click="addControl()">Add Button</button>
  <div id="content"></div>
  <div id="clicks"></div>
</div>

<p>Add multiple buttons and click the button that was added in the beginning. Notice the Clicks to be increased multiple times.</p>
<p>For instance, add a bunch of buttons and click Button 1</p>
&#13;
&#13;
&#13;

我希望click事件只针对特定元素触发一次。

3 个答案:

答案 0 :(得分:2)

问题是因为你多次编译#content DOM,因为你的旧元素再次被绑定点击事件到它。如果仔细观察,您会看到nth按钮与n-1点击事件绑定在一起。

以下是解释。

  1. 当您添加第一个按钮时,它会添加它并编译第一个按钮。

    • 现在#content有1个按钮,其中有1个点击事件绑定到它。
  2. 当你添加第二个按钮时,它会被添加到DOM中,但它会重新编译整个#content DOM,你知道它已经有了一个带有click事件的按钮。当您#content DOM时,它将再次重新编译第一个指令,并再次向其添加click事件。它也会点击事件到第二个按钮。

    • 现在#content有2个按钮
    • 第一个按钮有2个事件限制
    • 第二个按钮有1个事件限制
  3. 当您添加第3个按钮时,您将看到以下更改

    • 现在#content有2个按钮
    • 第一个按钮有3个事件限制
    • 第二个按钮有2个事件限制
    • 第3个按钮有1个事件限制
  4. 我说每次都不要通过重新编译DOM来自行渲染controls。假设您已经添加了对页面进行第100次控制,因为您无缘无故地重新编译99控件,从技术上讲这是没有意义的。因此,您应该将控制权交给ng-repeat

    <强>标记

    <div ng-controller="TestController">
        <button ng-click="addControl()">Add Button</button>
        <div ng-repeat="control in controls"><control count="{{control}}"></control></div>
        <div id="clicks"></div>
    </div>
    

    <强>控制器

    app.controller('TestController', function($scope, $compile) {
      $scope.count = 1;
      $scope.controls = [];
      $scope.controlsCount = 0;
      $scope.addControl = function() {
        $scope.controls.push(++$scope.controlsCount);
      };
    });
    

    Demo plunkr

答案 1 :(得分:1)

你绑定@object.as_json({except: [:created_at, :updated_at]}) 事件两次, enter image description here 因为指令在链接阶段被初始化两次,其中click处理程序被绑定,你通过click触发了摘要周期,它将事件附加到指令,因为它们处于链接阶段,但是事件可以绑定多次,因此指令有多个点击事件,首先建议是$compile(element.contents())(scope);事件优先

unbind

你可能会问,元素可能有多个点击事件,这里是如何

element.unbind('click').bind('click');

enter image description here

下面的工作示例

//event1
document.body.onclick = function(){ console.log('event1'); }

//event2
var oldClick = document.body.onclick;
document.body.onclick = function(){ console.log('event2'); oldClick.bind(document.body).call(); }

//this will trigger
event2
event1
var clicks = 0;
var app = angular.module('test', []);

app.directive('control', function($compile) {
  var linker = function(scope, element, attrs) {
    element.html('<button style="background:grey;">Button ' + scope.count + '</button>');
    element.unbind('click').bind('click', function() {
      clicks++;
      $('#clicks').html('Clicked ' + clicks + ' times')
    });
    $compile(element.contents())(scope);
  };

  return {
    restrict: 'E',
    scope: {
      count: '@'
    },
    link: linker
  }
});

app.controller('TestController', function($scope, $compile) {
  $scope.count = 1;
  $scope.addControl = function() {
    $('#content').append('<control count="' + $scope.count+++'"></control>');
    $compile($('#content').contents())($scope);
  };
});
#content {
  margin-top: 10px;
}
#clicks {
  margin-top: 10px;
}
p {
  color: grey;
}

答案 2 :(得分:-1)

你需要以有棱角的方式思考。

只需像这样重写你的链接功能

var linker = function(scope, element, attrs) {
 element.html('<button ng-click="onClick()"  style="background:grey;">Button ' + scope.count + ' Clicked {{clicks}} times</button>');

 scope.clicks=0;
 scope.onClick = function(){
  scope.clicks+;
 }
 $compile(element.contents())(scope);
};