Graham
Graham

Reputation: 1517

Angular custom directive with isolate scope not firing ng-click function

I have the following Angular custom directive code:

Template (ReviewStandards.html)

<div class="review-standard" ng-repeat="standard in standards">
    <button ng-click="mark(standard)">Mark Complete</button>
</div>

JS

app.directive("reviewStandards", function ($parse, $state) {
return {
    restrict: "A",
    templateUrl: function (elements, attrs) {
        return "/Scripts/App/Directives/Templates/ReviewStandards.html";
    },
    transclude: false,
    scope: {
        standards: "="
    },
    replace: true,
    link: function (scope, elem, attrs) {

        scope.mark = function (standard) {
            alert();
        };
    }
  };
});

The directive is used as:

<div review-standards standards="review.ReviewStandards"></div>

Where standards is just a JSON array of standard objects.

Problem is that the the ng-click is not firing the function when the button is clicked. The scope is isolated - is this something to do with this or the fact that the button is in an ng-repeat?

Upvotes: 1

Views: 807

Answers (2)

Maher
Maher

Reputation: 2547

Try This, "i just remove the Replace from your codes"

var app = angular.module("app", []);

app.controller("ctrl", function($scope) {

  $scope.data = [{
      name: "a"
    },
    {
      name: "b"
    }
  ];


});

app.directive("reviewStandards", function() {
  var template = "<div class=\"review-standard\">" +
     "<div ng-repeat=\"standard in standards\">" +
      "{{standard.name}} " +
      "<button ng-click=\"mark(standard)\">Mark Complete</button>" +
     "<div><hr>" +
    "</div>";
  return {
    restrict: "A",
    transclude: false,
    template: template,
    scope: {
      standards: "="
    },
    link: function(scope, elem, attrs) {

      scope.mark = function(standard) {
        console.log(standard)
      };
    }
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
  <div review-standards standards="data"></div>
</div>

Upvotes: 6

Grundy
Grundy

Reputation: 13381

I'll try a bit explain why this happens.

Problems here with scope inheritance when using replace:true and in template just one element with ng-repeat.

If replace:false, template paste inside element with directive, so you get something like this

<div review-standards standards="review.ReviewStandards"> <!-- here isolated scope from review-standards directive -->
    <div class="review-standard" ng-repeat="standard in standards"> <!-- here child scope created with ng-repeat -->
        <button ng-click="mark(standard)">Mark Complete</button>
    </div>
</div>

So, child scopes that created by ng-repeat inherits from isolated scope review-standards directive, and all property from isolated scope available in children scopes.

When used replace:true, template replace element with directive, si you get something like this

<div class="review-standard" ng-repeat="standard in standards" review-standards standards="review.ReviewStandards"> <!-- here child scope created with ng-repeat -->
    <button ng-click="mark(standard)">Mark Complete</button>
</div>

And most interesting in this case, that now children scopes inherited from ng-controller, but $parent property setup to isolated scope review-standards directive. So in children scope available all properties from ng-controller scope but not available from isolated scope review-standards directive.

Simplest way for solution, as suggest in nearby answer, just remove replace:true

Yet another way: a bit change template, like this

<div>
    <div class="review-standard" ng-repeat="standard in standards">
        <button ng-click="mark(standard)">Mark Complete</button>
    </div>
</div>

Or a bit ugly solution: use $parent property instead hoping on inheritance

<div class="review-standard" ng-repeat="standard in $parent.standards">
    <button ng-click="$parent.mark(standard)">Mark Complete</button>
</div>

Upvotes: 2

Related Questions