Angular Directive ng-click Not Working

19,032

Solution 1

In order to make ng-click directive work it needs to be processed('compiled') by angular infrastructure first, so instead of manually creating li elements in your directive about which angular doesn't have a clue they exist, you can use ng-repeat in directive template as follows (no need for manually creating DOM elements):

angular.module('app.directives', [])
 .directive('process', function() {
    return {
        restrict: 'E'
      , replace: true
      , template: '<ol class="nav nav-pills"><li ng-class="{active: stage==at}" ng-click="stage.select()" ng-repeat="stage in stages"><a>{{stage.label}}</a></li></ol>'
      , scope: {
            stages: "="
          , at: "="
        }
    }
  });

Modified plunker: http://plnkr.co/edit/SW1Ph0nIjVYW3UzixtBx?p=preview

I think it's most elegant solution. Of course you can move template to eternal file and reference it via templateUrl.

Alternatively you could use $compile service on element after you added li items manually but it feels like a hack.

Solution 2

Working url http://plnkr.co/edit/3zuDuQDjhA5UY5nLD09Z?p=preview

Please make below change in url directive

angular.module('app.directives', [])
 .directive('process', function($compile) {
    return {
        restrict: 'E'
      , replace: true
      , template: '<ol class="nav nav-pills"></ol>'
      , scope: {
            stages: "="
          , at: "="
        }
      , link: function postLink(scope, element, attrs) {
          for (var i = 0; i < scope.stages.length; i++) {
            var $stage = $('<li ng-click="stages['+i+'].select()"><a>'+scope.stages[i].label+'</a></li>');
            if (scope.at == scope.stages[i]) {
              $stage.addClass('active');
            }
            $(element).append($stage);
            $compile($(element))(scope);
          }
        }
    }
  });

i have injected $complie and added one line $compile($(element))(scope);

Share:
19,032
jtfairbank
Author by

jtfairbank

Updated on June 08, 2022

Comments

  • jtfairbank
    jtfairbank about 2 years

    Plunker

    I have an external controller that contains a directive inside of its view. The directive gets a list of process points and generates links where you can select each one. It correctly sets up the HTML in the link function, but the links' ng-click actions don't work.

    Any ideas? :)

    Code for the Non-Plunkering

    HTML

    <!DOCTYPE html>
    <html>
    
      <head><link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
            <script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
            <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
        <script src="script.js"></script>
      </head>
    
      <body ng-app="app">
        <div ng-controller="widget">
          <process stages="production" at="productionAt"></process>
        </div>
      </body>
    
    </html>
    

    JS

    angular.module('app', ['app.directives', 'app.controllers']);
    
    angular.module('app.controllers', [])
     .controller('widget', function($scope) {
        var selectStage = function () {
          alert(this.label + " selected.");
          $scope.processAt = this;
        }
    
        $scope.production = [
            {label: "Starting", select: selectStage}
          , {label: "Fermenting", select: selectStage}
          , {label: "Pouring",     select: selectStage}
          , {label: "Beer!",  select: selectStage}
        ];
    
        $scope.productionAt = $scope.production[0];
     });
    
    angular.module('app.directives', [])
     .directive('process', function() {
        return {
            restrict: 'E'
          , replace: true
          , template: '<ol class="nav nav-pills"></ol>'
          , scope: {
                stages: "="
              , at: "="
            }
          , link: function postLink(scope, element, attrs) {
              for (var i = 0; i < scope.stages.length; i++) {
                var $stage = $('<li ng-click="stages['+i+'].select()"><a>'+scope.stages[i].label+'</a></li>');
                if (scope.at == scope.stages[i]) {
                  $stage.addClass('active');
                }
                $(element).append($stage);
              }
            }
        }
      });