Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular JS: Why is my click event firing twice?

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 ($compile) {

    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>");
                $compile(element.contents())(scope)
            }
        }
    }
})
like image 326
user648869 Avatar asked Aug 20 '13 00:08

user648869


2 Answers

It is because you are compiling the element.contents(), including the <a> with ng-click, which should be already compiled. At the time you call a manual compile, it gets compiled 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);
        $compile(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

like image 83
Mr. Duc Nguyen Avatar answered Oct 31 '22 10:10

Mr. Duc Nguyen


@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 completed 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 completed flag to this element
    element.attr('collection-linked', true);

    // continue your linking ...
}
like image 42
Dustin Avatar answered Oct 31 '22 12:10

Dustin