Reputation: 2970
Basically I have 2 directives:
The radar-chart
directives is instantiated by:
<radar-chart data="" labels="" options="" colours=""></radar-chart>
The user-radar-chart
directive is instantiated by:
<user-radar-chart preseverence="20" motivation="39"></user-radar-chart>
Now the user-radar-chart
should use the radar-chart
directive but with a fixed set of labels, colours and options, only the data should be different.
How can I do this?
This is what I have tried:
angular
.module('myApp')
.directive('userRadarChart', function () {
return {
restrict: 'E',
template: '<canvas class="chart radar-chart" data="{{data}}" labels="{{labels}}" options="{{options}}" colours="{{colours}}"></canvas>',
scope: {
motivation: '@',
preseverence: '@'
},
link: function ($scope, $element, $attrs) {
$scope.data = [$attrs.motivation, $attrs.preseverence];
$scope.labels = ['Motivation', 'Preseverence'],
$scope.options = {};
$scope.colours = ['Yellow'];
}
}
})
Upvotes: 0
Views: 138
Reputation: 19098
There are several different ways of doing this. The simplest (which I think is what you are getting at with your example) way is to have the template of user-radar-chart
create a radar-chart
directive:
This example shows that userRadarChart is just a radar chart with the color
option preset.
.directive('radarChart', function() {
return {
restrict: 'E',
template: "<span>I am a {{color}} radar chart, with data:</span>\
<pre>{{ data | json }}</pre>",
scope: {
data: "=",
color: '@'
},
link: function (scope, element){
element.css('background-color', scope.color);
}
}
})
.directive('userRadarChart', function() {
return {
restrict: 'E',
scope: { data: "=" },
template: '<radar-chart data="data" color="green"></radar-chart>'
}
});
angular.module('myApp', [])
.controller('MyController', function () {
this.data1 = {
foo: 'bar'
}
this.data2 = {
dog: 'bone'
}
})
.directive('radarChart', function() {
return {
restrict: 'E',
template: "<span>I am a {{color}} radar chart, with data:</span>\
<pre>{{ data | json }}</pre>",
scope: {
data: "=",
color: '@'
},
link: function (scope, element){
element.css('background-color', scope.color);
}
}
})
.directive('userRadarChart', function() {
return {
restrict: 'E',
scope: { data: "=" },
template: '<radar-chart data="data" color="green"></radar-chart>'
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController as ctrl">
<radar-chart color="red" data="ctrl.data1"></radar-chart>
<user-radar-chart data="ctrl.data2"></user-radar-chart>
</div>
</div>
Note that watchers aren't required for the above because we are using =
so the data
value is taking advantage of angular's built in two way data binding.
Another option is to have the user-radar-chart
settings stored inside the radar-chart
directive, and just have a type
attribute on the radar-chart
which would configure the chart for you:
.directive('radarChart', function() {
return {
restrict: 'E',
scope: {
data: "=",
color: '@'
},
link: function (scope, element, attrs){
if (attrs.type === "user")
// define user-radar-chart settings here.
scope.color = 'green';
element.css('background-color', scope.color);
}
}
});
There are many more ways of doing this, but if the subcharts you're making really are as simple as just changing settings, I think either of the above ways are how it should be done - keep it simple.
Upvotes: 1
Reputation: 54741
I'm not sure why you're using <canvas>
in your template when you say you want to use <radar-chart>
, but I'm going to guess this is the problem.
There is no abstraction of directives in Angular. You could use inheritance for the directive's controller, but the link function and the directive can not be abstracted.
You can use other Angular directives inside the template for a directive, and I think this is what you're missing.
angular
.module('myApp')
.directive('userRadarChart', function () {
return {
restrict: 'E',
template: '<radar-chart data="{{data}}" labels="[\'Motivation\', \'Perseverance\']" options="{}" colours="[\'Yellow\']"></radar-chart>',
scope: {
motivation: '@',
perseverance: '@'
},
link: function ($scope, $element, $attrs) {
$scope.$watchGroup(['motivation','perseverance'],function(values) {
$scope.data = values;
});
}
}
});
Keep in mind that you should try to use watchers when possible. If the values for motivation and perseverance are bound to an Angular expression, then the chart won't update if they change.
Using a $scope.$watchGroup
executes the callback function with an array of values whenever they change. When you assign attributes to the scope using @
they already exist in the scope. So you shouldn't use $attrs.motivation
to access them.
I moved your static parameters to the template. Try to keep style and display in the template, and business logic in the code. Makes it easier to maintain.
Upvotes: 1