I'm trying to create a d3 chart using an Angular directive. I manage to create it, but the problem is that I want some ng-click events on the chart elements and I'm not really sure how this should be done.
Here is my directive:
.directive('circleChart', function($parse, $window, $compile) {
return {
restrict: 'A',
scope: {
datajson: '='
},
link: function(scope, elem, attrs) {
var circleChart = new CircleChart(scope.datajson);
circleChart.initialise(scope);
var svg = circleChart.generateGraph();
svg = angular.element(svg);
console.log(svg);
//scope.$apply(function() {
var content = $compile(svg)(scope);
elem.append(content);
//});
}
}
});
The CircleChart object creates my d3 chart and there is the place I attach an ng-click attribute to the chart elements (doesn't seem to be a proper Angular way of doing it):
var CircleChart = Class.create({
initialise: function(scope) {
this.datajson = scope.datajson;
},
generateGraph: function() {
.............
var chartContent = d3.select("div#chart-content");
var svg = chartContent.append("svg")
.attr("id", "circle")
.attr("width", diameter)
.attr("height", diameter)
.style("border-radius", "50px")
.append("g")
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
...............
var circle = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("class", function(d) {
return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root";
})
.attr("id", function(d) {
return d.id;
})
.attr("value", function(d) {
return d.name
})
.attr("parent", function(d) {
if (d.parent) return d.parent['id']
})
.attr("ng-click", function(d) {
return "getEgs('" + d.id + "')";
})
...............
The d3 code is working fine because if I remove the compile code from the directive, the chart gets drawn, but the ng-clicks don't fire.
If I leave the compile code there, it goes into an infinite loop and the browser is building up memory until I have to kill it.
Obviously, my method is not working and it will be awesome if someone can help me out
Since you are modifying the DOM from inside the CircleChart.generateGraph
and re-appending the contents of the element in you directive: elem.append(content)
after compilation, you (probably) end up in an infinite loop.
If you do want to compile the template thus produced, you can simple call $compile(elem.contents())(scope);
without having to clear
and append
the content again. $compile
will work Angular magic on the DOM in-place.
However, as I suggested in the comments, since you have access to the whole scope in CircleChart
(which in my opinion is probably an overkill), you should capture the click event in d3
and invoke the getErgs
function from code instead of $compile
-ing the code and delegating the task to Angular.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With