Search code examples
javascriptangularjsdomangularjs-scopeangularjs-compile

ng-click fired multiple times after compile


I have read many SO answer but couldn't resolve the problem.

I have a Javascript function that create HTML element like document.createElement(...)

This is a part of that function :

var div=document.getElementById(params.wrapper);
div.setAttribute("ng-controller","ProjectController");

var button = document.createElement('button');
button.setAttribute('id','btn-view-users-' + params.id);
button.className='button-manage-user';
button.setAttribute('ng-click','hello()');
div.appendChild(button);

This function is called at the start of the application and create many rows so when the page is loaded the HTML generated by the function look like this : (this sample code is simplified to be more comprehensible)

<div id="wrapper" class="wrapper ng-scope" ng-controller="ProjectController">
    <button id="btn-view-users-310" class="button-manage-user" ng-click="hello()">Manage Users</button>
    <button id="btn-view-users-311" class="button-manage-user" ng-click="hello()">Manage Users</button>
    <button id="btn-view-users-312" class="button-manage-user" ng-click="hello()">Manage Users</button>
    <button id="btn-view-users-313" class="button-manage-user" ng-click="hello()">Manage Users</button>
</div>

The Angular controller :

app.controller('ProjectController',
    ['$scope', '$http',
        function($scope, $http) {
             $scope.hello = function(){
                console.log("hello")
             }
        }
    ]
)

At the end of the function when all elements are created I compile with :

var content = $(".wrapper");
angular.element(document).injector().invoke(function($compile) {
    var scope = angular.element(content).scope();
    $compile(content)(scope);
    console.log("#compile")//log appears in the console 10 times if 10 elements are created.
});

But when I click on the button the "hello" is fired many times !

If I have 10 elements on the page and click on the first element it is fire 10 times, if I click on the second element it is fired 9 times and so on..

I have tried to move the ng-controller declaration inside the button button.setAttribute("ng-controller","ProjectController"); Or even in the <body> tag but I still get the same behavior.

Thanks for you help


Solution

  • Its because you are compiling the controller div, Which will do compile ng-controller="ProjectController" directive and will register instance of your ProjectController as many times you compile the div.

    You should do $compile(content.contents())(scope); instead of compiling whole controller element.

    But compile element should have only one root element like in your case you can not do that, because element which you wanted to compile should have exact one root element. Other should be child element of that root.