Javascript AngularJS:动态绑定点击指令被多次触发

Javascript AngularJS:动态绑定点击指令被多次触发,javascript,jquery,angularjs,angularjs-directive,angularjs-scope,Javascript,Jquery,Angularjs,Angularjs Directive,Angularjs Scope,我尝试动态添加字段,并在指令的链接函数中绑定单击事件。但当我添加更多字段时,它似乎会多次开火。请参见下面的示例- var点击次数=0; var app=角度模块('测试',[]); 应用程序指令('control',函数($compile){ 变量链接器=函数(范围、元素、属性){ html('Button'+scope.count+''); 元素绑定('单击',函数(){ 点击++; $('#clicks').html('Clicked'+clicks+'times')) }); $comp

我尝试动态添加字段,并在指令的
链接
函数中绑定
单击
事件。但当我添加更多字段时,它似乎会多次开火。请参见下面的示例-

var点击次数=0;
var app=角度模块('测试',[]);
应用程序指令('control',函数($compile){
变量链接器=函数(范围、元素、属性){
html('Button'+scope.count+'');
元素绑定('单击',函数(){
点击++;
$('#clicks').html('Clicked'+clicks+'times'))
});
$compile(element.contents())(范围);
};
返回{
限制:'E',
范围:{
计数:'@'
},
链接:链接器
}
});
app.controller('TestController',函数($scope,$compile){
$scope.count=1;
$scope.addControl=函数(){
$(“#内容”)。追加(“”);
$compile($('#content').contents())($scope);
};
});
#内容{
边缘顶部:10px;
}
#咔哒声{
边缘顶部:10px;
}
p{
颜色:灰色;
}

添加按钮
添加多个按钮,然后单击开头添加的按钮。请注意,单击次数将增加多次


例如,添加一组按钮,然后单击按钮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);
};
var linker=函数(范围、元素、属性){
html('Button'+scope.count+'Clicked{{clicks}}次');
scope.clicks=0;
scope.onClick=function(){
范围.点击+;
}
$compile(element.contents())(范围);
};

您正在绑定
单击事件两次,
因为指令在链接阶段被初始化了两次,点击处理程序在链接阶段被绑定,所以您通过
$compile(element.contents())(scope)触发了摘要循环
哪个事件附加到指令,因为它们处于链接阶段,但事件可以绑定多次,所以指令有多个单击事件,第一个建议是先解除绑定
事件

element.unbind('click').bind('click');
您可能会问,元素可能有多个单击事件,这是如何发生的

//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点击次数=0;
var app=角度模块('测试',[]);
应用程序指令('control',函数($compile){
变量链接器=函数(范围、元素、属性){
html('Button'+scope.count+'');
元素。取消绑定('click')。绑定('click',函数(){
点击++;
$('#clicks').html('Clicked'+clicks+'times'))
});
$compile(element.contents())(范围);
};
返回{
限制:'E',
范围:{
计数:'@'
},
链接:链接器
}
});
app.controller('TestController',函数($scope,$compile){
$scope.count=1;
$scope.addControl=函数(){
$(“#内容”)。追加(“”);
$compile($('#content').contents())($scope);
};
});
#内容{
边缘顶部:10px;
}
#咔哒声{
边缘顶部:10px;
}
p{
颜色:灰色;
}

添加按钮
添加多个按钮,然后单击开头添加的按钮。请注意,单击次数将增加多次


例如,添加一组按钮并单击按钮1

问题在于您多次编译
#content
DOM,因为您的旧元素再次绑定到它。如果仔细观察,您将看到第n个按钮绑定了
n-1
单击事件

下面是解释

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

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

    • 现在
      #content
      有2个按钮
    • 第一个按钮有两个绑定到它的事件
    • 第二个按钮有1个绑定到它的事件
  • 当您添加第三个按钮时,您将看到下面的更改

    • 现在
      #content
      有2个按钮
    • 第一个按钮有3个绑定到它的事件
    • 第二个按钮有两个绑定到它的事件
    • 第三个按钮有一个绑定到它的事件
  • 我想说的是,不要每次都通过重新编译DOM,自己在表单上呈现
    控件。假设您在页面上添加了第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>
    

    我认为这不是解决办法。我明白我做错了什么。每次我添加一个控件时,我都会重新编译它的父控件的内容。我认为,您需要以
    angular
    的方式进行思考。在
    angular
    代码中使用
    jQuery
    是一种糟糕的做法。为什么我的答案没有被打分/投票?有什么想法/建议吗?我可以知道它背后的原因吗?请添加注释,以便我知道哪里出了问题,从而改进我。@Medttleukuly问题在于每次创建新控件时我都在编译
    #content
    (正如Pankaj所指出的)。尽管解绑有效,但我不认为这是解决我问题的实际办法。@AswinRamakrishnan,但我不明白为什么我的答案会被否决?你有什么想法吗:(你只有
    元素。解除绑定('click')。绑定('click');
    这部分是正确的..但解释不中肯..你能看看我的答案吗..你会更好地了解它为什么会发生。谢谢:-)我编辑了我的答案,更详细一点。如果你什么都不懂,请告诉我。我是说你对我答案的编辑会很棒
    app.controller('TestController', function($scope, $compile) {
      $scope.count = 1;
      $scope.controls = [];
      $scope.controlsCount = 0;
      $scope.addControl = function() {
        $scope.controls.push(++$scope.controlsCount);
      };
    });