【问题标题】:Angular ng-click's inside a dynamically created d3 chart are not working动态创建的 d3 图表中的 Angular ng-click 不起作用
【发布时间】:2015-07-15 07:35:54
【问题描述】:

我正在尝试使用 Angular 指令创建 d3 图表。我设法创建了它,但问题是我想要图表元素上的一些 ng-click 事件,我不确定应该如何完成。

这是我的指令:

.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);
                //});
            }
        }
    });

CircleChart 对象创建了我的 d3 图表,并且我在图表元素上附加了一个 ng-click 属性(这似乎不是正确的 Angular 方法):

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 + "')";
                })

    ...............

d3 代码工作正常,因为如果我从指令中删除编译代码,图表会被绘制,但不会触发 ng-click。

如果我将编译代码留在那里,它会进入一个无限循环,并且浏览器正在建立内存,直到我不得不杀死它。

显然,我的方法不起作用,如果有人可以帮助我,那就太棒了

【问题讨论】:

  • generateGraph 函数中的svg 是什么?那是分离的DOM吗?另外,在我看来,从代码生成角度模板并不是一个好主意。我这样做的方法是在初始化或调用期间将回调传递给CircleChart,在 d3 中捕获点击事件并通过 Javascript 代码调用该回调。
  • @musically_ut 我用 svg 创建代码更新了我的问题。我试图理解你所说的关于传递回调的内容。你指的是我想用 ng-click 调用的实际函数吗?如果我在指令中使用控制器的范围,我可能可以访问它。
  • 是的,我宁愿你在.on('click', ...)中调用函数getEgs,而不是在代码中输出ng-click

标签: javascript angularjs d3.js


【解决方案1】:

由于您正在从 CircleChart.generateGraph 内部修改 DOM 并在编译后在指令中重新附加元素的内容:elem.append(content),因此您(可能)最终陷入无限循环。

如果您确实想编译这样生成的模板,您可以简单地调用$compile(elem.contents())(scope);,而无需再次调用clearappend 的内容。 $compile 将在 DOMin-place 上使用 Angular 魔法。


但是,正如我在 cmets 中所建议的那样,由于您可以访问 CircleChart 中的整个范围(在我看来这可能是一种矫枉过正),您应该在 d3 中捕获点击事件并调用 @987654329 @ 代码中的函数而不是 $compile-ing 代码并将任务委托给 Angular。

【讨论】:

  • 感谢您的回答,我现在设法让它工作。我所做的是在指令controller: 'egCtrl' 中访问我的控制器,然后我没有将getEgs() 放在控制器的$scope 上,而是将其添加为一个属性,例如:this.getEgs = function() {}。然后如你所说,我使用d3的on.('click', ...)
最近更新 更多