Reputation: 21147
I've been playing around with directives for the first time today and am trying to build a reusable progress bar directive (based on Bootstrap 3.0) that I can dynamically have fill up or empty based on a value. The directive definition is as follows:
directive('progressBar', function () {
var success = 'progress-bar progress-bar-success';
var warning = 'progress-bar progress-bar-warning';
var danger = 'progress-bar progress-bar-danger';
var setCssStyling = function (width) {
if (width >= 50) {
return success;
} else if (width >= 20) {
return warning;
} else {
return danger;
}
}
var formatWidth = function (width) {
return 'width: ' + width + '%';
}
return {
restrict: 'E',
scope: {},
template: '<div class="progress progress-striped active">' +
'<div ng-class="cssStyle" role="progressbar" style="{{ width }}"></div>' +
'</div>',
link: function (scope, element, attrs) {
if (attrs.width) {
scope.width = formatWidth(attrs.width);
} else {
scope.width = formatWidth(0);
}
scope.$watch(attrs.width, function (newVal) {
scope.width = formatWidth(newVal);
scope.cssStyle = setCssStyling(newVal);
});
}
}
});
This works exactly as planned given these test usages:
<progress-bar width="100"></progress-bar>
<progress-bar width="45"></progress-bar>
<progress-bar width="15"></progress-bar>
What I was hoping to do was be able to dynamically bind the width attribute to a changing value in my controller such that the width and styling of the progress bar would move. I tried binding to a value in my controller that changed every second:
<progress-bar width="{{ today.seconds }}"></progress-bar>
But when I examine the scope for that progress-bar the width is always set to width: undefined%
. Is there a better way to accomplish dynamically updating content like this or am I missing something when it comes to scope or something silly?
Upvotes: 0
Views: 78
Reputation: 552
In your directive you need to use
scope: { width: '=' }
=
this kind of parameter says to angular to create a bi-directional parameter in your directive scope, so, if you change it's value in your directive your controller will be affected and if you change this value in your controller your directive will be reflected
Upvotes: 1
Reputation: 1044
You are using scope.$watch
on attrs.width
, which means it shouldn't be an interpolation. So you should simply do <progress-bar width="today.seconds"></progress-bar>
.
If you'd prefer to be able to use an interpolation, you'd use scope.$observe
, and you'd also want to parse the width (as the interpolation will return a string).
Update: since you've set up an isolate scope (scope: {}
) you will need to bind width
in your scope hash object.
return {
restrict: 'E',
scope: { width: '='},
template: '<div class="progress progress-striped active">' +
'<div ng-class="cssStyle" role="progressbar" style="{{ cssWidth }}"></div>' +
'</div>',
link: function (scope, element, attrs) {
scope.cssWidth = '';
scope.$watch('width', function (newVal) {
scope.cssWidth = formatWidth(newVal);
scope.cssStyle = setCssStyling(newVal);
});
}
}
Of course you can also just ditch the isolate scope if that makes sense in your context. Also you could drop cssWidth
all together and simply do your formatting in the style
attribute.
http://plnkr.co/edit/Zx1fgHYyXuxByHH6YorP
Upvotes: 1