Reputation: 3
I'm trying to customize a template within a directive and include references to attributes in the parent scope. I'm pretty new to Angular but I've done a fair bit of searching and I've based my attempts on Customizing the template within a Directive. However if I pass a reference to a parent scoped variable as an attribute to the directive it doesn't get resolved, possibly because it's still undefined at the time the compile function is called.
My directive definition looks like this:
app.directive('sectionHeader', function() {
return {
restrict: 'EC',
replace: true,
transclude: true,
scope: {sectionName:'@sectionName', imageUrl:'@imageUrl'},
compile: function(element, attrs) {
var imageHtml = attrs.hasOwnProperty('imageUrl') ? '<div style="float: left; padding-right: 5px;"><img class="float_left" src="' + attrs.imageUrl + '" alt=""/></div>' : '';
var htmlText =
'<div>' + imageHtml + '<h1 class="float-left">' + attrs.sectionName + '</h1>' +
'<div class="clear"></div>' +
'<div class="modal_hr"></div></div>';
element.replaceWith(htmlText);
},
};
});
And I'm using the directive like this:
<div class="section-header" section-name="{{currentFeatureName}}"></div>
The problem is the {{currentFeatureName}} variable from my controller doesn't appear to be defined when the compile function is called on the directive.
One way I've considered to get around this is within the compile function set up an observer function on the sectionName attribute that updates h1 element content when it sees a change. This seems a little clunky and I was wondering if there is a better or more elegant way of doing this.
Upvotes: 0
Views: 3219
Reputation: 60396
Check out the $observe
function in Directive docs.
But beside that, there actually seems to be no need to do what you were trying to do. See:
var app = angular.module('plunker', []);
app.controller('AppController',
[
'$scope',
function($scope) {
$scope.currentFeatureName = 'Current Feature Name';
$scope.imageUrl = "https://lh3.googleusercontent.com/GYSBZh5RpCFwTU6db0JlHfOr_f-RWvSQwP505d0ZjWfqoovT3SYxIUPOCbUZNhLeN9EDRK3b2g=s128-h128-e365";
}
]
);
app.directive('sectionHeader', function() {
return {
restrict: 'EC',
replace: true,
transclude: true,
scope: {
sectionName:'@',
imageUrl:'@'
},
template: '<div><div style="float: left; padding-right: 5px;" ng-show="imageUrl"><img class="float_left" ng-src="{{imageUrl}}" alt=""/></div><h1 class="float-left">{{sectionName}}</h1><div class="clear"></div><div class="modal_hr"></div></div>'
};
});
HTML:
<div ng-controller="AppController">
<div class="section-header" section-name="{{currentFeatureName}}" image-url="{{imageUrl}}"></div>
</div>
Upvotes: 1
Reputation: 120513
You are correct on why this isn't working. Interpolated attributes are not available when the compile and link functions run because no digest has occurred yet to resolve the interpolation to a value. You can read more about this here. You are also right about the solution: use attrs.$observe( 'sectionName', function ( val ) { ... });
However, it doesn't look like you need a dynamic template. If this was your template:
<div>
<div style="float: left; padding-right: 5px;" ng-show="{{imageUrl}}">
<img class="float_left" ng-src="{{imageUrl}}" alt="" />
</div>
<h1 class="float-left">{{sectionName}}</h1>
<div class="clear"></div>
<div class="modal_hr"></div>
</div>
Then you wouldn't need any logic in a compile or link function. Perhaps this pattern will also help you.
Upvotes: 1