最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular JS: Why is my click event firing twice? - Stack Overflow

programmeradmin5浏览0评论

I have the following code. It loops over JSON to produce a nested ul list. I have a click event that executes the function toggleNav() bound to a anchor tag. I don't know why the click event is bound twice to the element. Also I am new to angular, is there a document that explains this concept out there? Thanks!

define([
'/assets/angularapp/AppDirectives.js',
'highstock'
], function (directives) {
directives.directive('collection', function () {
    return {
        restrict: "E",    //declare by element
        replace: true,
        scope: {
            collection: '='
        },
        template: "<ul class=\"nav nav-list tree\"><member ng-repeat=\"member in collection\" member=\"member\"></member></ul>"
    }
})

directives.directive('member', function ($pile) {

    return {
        restrict: "E",
        replace: true,
        scope: {
            member: '='
        },
        template: "<li ng-show=\"member.open\"><span><input type=\"checkbox\" ng-model=\"member.selected\" class=\"sideChkbox\"><a class=\"tree-toggle\" ng-click=\"toggleNav()\"><i class=\"icon-chevron-right\"></i>{{member.data}}</a></span></li>",
        controller: function($scope, $element){
            $scope.toggleNav = function(){
                angular.forEach($scope.member.children,function(child,key){
                    if(child.open==true){
                        alert("a")
                        child.open=false;
                    } else {
                        child.open=true;
                        alert("b")

                    }

                })

            }
        },
        link: function (scope, element, attrs) {
            if (angular.isArray(scope.member.children)) {
                 element.append("<collection collection='member.children'></collection>");
                $pile(element.contents())(scope)
            }
        }
    }
})

I have the following code. It loops over JSON to produce a nested ul list. I have a click event that executes the function toggleNav() bound to a anchor tag. I don't know why the click event is bound twice to the element. Also I am new to angular, is there a document that explains this concept out there? Thanks!

define([
'/assets/angularapp/AppDirectives.js',
'highstock'
], function (directives) {
directives.directive('collection', function () {
    return {
        restrict: "E",    //declare by element
        replace: true,
        scope: {
            collection: '='
        },
        template: "<ul class=\"nav nav-list tree\"><member ng-repeat=\"member in collection\" member=\"member\"></member></ul>"
    }
})

directives.directive('member', function ($pile) {

    return {
        restrict: "E",
        replace: true,
        scope: {
            member: '='
        },
        template: "<li ng-show=\"member.open\"><span><input type=\"checkbox\" ng-model=\"member.selected\" class=\"sideChkbox\"><a class=\"tree-toggle\" ng-click=\"toggleNav()\"><i class=\"icon-chevron-right\"></i>{{member.data}}</a></span></li>",
        controller: function($scope, $element){
            $scope.toggleNav = function(){
                angular.forEach($scope.member.children,function(child,key){
                    if(child.open==true){
                        alert("a")
                        child.open=false;
                    } else {
                        child.open=true;
                        alert("b")

                    }

                })

            }
        },
        link: function (scope, element, attrs) {
            if (angular.isArray(scope.member.children)) {
                 element.append("<collection collection='member.children'></collection>");
                $pile(element.contents())(scope)
            }
        }
    }
})
Share Improve this question asked Aug 20, 2013 at 0:23 user648869user648869 2517 silver badges14 bronze badges 6
  • Can you throw together a fiddle showing this, I don't see anything obvious that should be triggering two calls to the handler. But being able to inspect the DOM after using the directives may lead to some insight. Also are you sure you're not just getting multiple iterations of your loop within the handler it is in fact calling the handler multiple times? – shaunhusain Commented Aug 20, 2013 at 0:28
  • Are you talking about the foreach loop triggers two alerts? It maybe the collection contains two elements, but the function is still bound once. – zs2020 Commented Aug 20, 2013 at 0:33
  • 1 I made a fiddle to check out the issue, I see exactly what you're saying and honestly no idea why it's happening: jsfiddle/rEz52/1 – shaunhusain Commented Aug 20, 2013 at 3:00
  • Only time I've had that happen was when I accidentally included app.js twice on the page - nothing similar happening? – Anders Bornholm Commented Aug 20, 2013 at 11:41
  • 2 Thanks for your help. I figured out what is happening. The member directive is inside of a loop. So the click function is getting bound to all the li elements in every iteration. So the latest li will get one click bound to it, but the prior one will have a second click bound to it, and so forth. I am thinking to bind to a unique id to avoid the duplicate binding. Again, I am new to angular I am thinking theres a better way to do this. – user648869 Commented Aug 21, 2013 at 5:00
 |  Show 1 more ment

2 Answers 2

Reset to default 13

It is because you are piling the element.contents(), including the <a> with ng-click, which should be already piled. At the time you call a manual pile, it gets piled again.

you can fix it by this:

    ...
    if (angular.isArray(scope.member.children)) {
        var newMemEL = angular.element("<collection collection='member.children'></collection>");
        element.append(newMemEL);
        $pile(newMemEL)(scope);
    }
    ...

It looks like you are trying to create a treeview, in this case, it would be better to use ngInclude instead of creating custom directives, have a look at this plunker, note that it will not work with Angular 1.2.0rc1 due to this issue

@Mr.DucNguyen's answer is correct, but if you don't want to further manipulate the DOM, you can approach it another way.

Flag the element as pleted during the link function, so when it tries to link again it fails.

link: function (scope, element, attrs) {
    // stop an already linked element from continuing
    if (element.attr('collection-linked')) {
        return;
    }
    // otherwise, add a pleted flag to this element
    element.attr('collection-linked', true);

    // continue your linking ...
}
发布评论

评论列表(0)

  1. 暂无评论