blaster blaster -4 years ago 104
AngularJS Question

String Interpolation Won't Work when Setting Attribute Values on a Custom Directive

Should I be able to pass attributes from the $scope into a custom directive like this?

<div ng-repeat="ratable in ratables">
<div>How much do you like {{ratable.name}}?</div>

<!-- CONFUSED - First element does not work, second element does -->
<rating currentRatingValue="{{ratable.currentvalue}}" maxRatingValue="10"></rating>
</div>


The hardwired "10" passes through into the directive just fine, but the string interpolation when I try to pass {{ratable.currentvalue}} never seems to occur. Am I doing something obviously wrong?

http://jsfiddle.net/ADukg/2168/

var myApp = angular.module('myApp',[])
.directive("rating", function () {
return {
restrict: "E",
scope: {},
template: "<div class='rating'>Current rating: {{currentratingvalue}} out of {{maxratingvalue}}</div>",
link: function (scope, element, attributes) {
console.log(attributes.currentratingvalue); // Does not work but seems like it should
console.log(attributes.maxratingvalue); // Does work
}
};
});

function MyCtrl($scope) {
$scope.name = 'Superhero';

$scope.ratables = [
{ name: "sledding", currentvalue: 3, maxvalue: 5 },
{ name: "water skiing", currentvalue: 7, maxvalue: 10 },
{ name: "whitewater rafting", currentvalue: null, maxvalue: 10 }
];
}

<div>
<div ng-controller="MyCtrl">
Hello, {{name}}!

<div ng-repeat="ratable in ratables">
<div>How much do you like {{ratable.name}}?</div>

<!-- CONFUSED - First element does not work, second element does -->
<rating currentRatingValue="{{ratable.currentvalue}}" maxRatingValue="10"></rating>
</div>
</div>
</div>

Answer Source

A few things:

  • directive attributes in HTML need to use kebab-case
  • you don't need an isolate scope (in fact it is causing problems); instead use scope: true
  • you need to set local scope properties so your template can pick them up
  • $observe must be used to get the value of interpolated attributes (i.e., attributes that use {{}}s)

HTML:

<rating current-rating-value="{{ratable.currentvalue}}" max-rating-value="10"></rating>

Directive:

link: function (scope, element, attributes) {
   attributes.$observe('currentRatingValue', function(newValue) {
      console.log('newValue=',newValue);
      scope.currentRatingValue = newValue
   })
   scope.maxRatingValue = attributes.maxRatingValue;
   console.log('mrv=',attributes.maxRatingValue);
}

Fiddle


Here is a version that uses an isolate scope:

.directive("rating", function () {
   return {
      restrict: "E",
      scope: { currentRatingValue: '@',
               maxRatingValue:     '@' },
      template: "<div class='rating'>Current rating: {{currentRatingValue}}"
              + " out of {{maxRatingValue}}</div>",
  };    
});

Fiddle

If you want to see the value of an isolate scope property in your link function, you'll need to use $observe or $watch because we used '@'. If you use '=' (for two-way databinding), you don't need to use $observe or $watch.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download