1

我将 D3 svg 图像包装在角度指令中。当用户单击该 D3 图像时,我想在控制器中将变量设置为 true,以便 ng-show 然后显示另一个 D3 图像。

我所做的是.on("click")向 D3 图像添加一个函数,并在该函数中用于$rootScope.$emit()发送事件。在第二张图像的控制器中,我有一个$rootScope.$on()ctach 事件并将 ng-show 的变量设置为 true。

这种方法行不通。我已经测试了代码以确保事件被正确地发出和捕获,但是 ng-show 没有显示第二个 D3 图像。

为什么是这样?

我创建了一个小 plunkr 来说明我正在尝试做的事情。 http://plnkr.co/edit/FnqeAF9kVXxdUdOzT5to

控制器代码如下:

function CircleCtrl($rootScope) {

    this.render = function(element, attrs) {
        var svg = d3.select(element[0]).append("svg")
            .attr("width", 200)
            .attr("height", 200);

        var circle = svg.append("circle")
            .attr("cx", 30)
            .attr("cy", 30)
            .attr("r", 20);
        circle.on("click", function(d,i) {
            var data = {val0: "zero", val1: "one"};
            $rootScope.$emit("Circle Clicked", data);
        });
    };

}

function SquareCtrl($rootScope) {
    this.showSquare = false;

    $rootScope.$on("Circle Clicked", function(event, data) {
        this.showSquare = true;
    })

    this.render = function(element, attrs) {
        var svg = d3.select(element[0]).append("svg")
            .attr("width", 200)
            .attr("height", 200);

        var rectangle = svg.append("rect")
            .attr("x", 10)
            .attr("y", 10)
            .attr("width", 50)
            .attr("height", 100);
    };

    }

    angular.module("AngularD3Example")
        .controller("CircleCtrl", ["$rootScope", CircleCtrl])
        .controller("SquareCtrl", ["$rootScope", SquareCtrl]);
4

1 回答 1

2

从外部 Angular 上下文更改 Angular 的范围不会更新范围变量和绑定,因为它不会运行 Angular 的摘要循环。在这种情况下,您正在使用事件click到 Angular 上下文。

您需要$apply()在范围上运行方法$rootScope来运行摘要循环将有效地更新绑定。

代码

circle.on("click", function(d,i) {
    var data = {val0: "zero", val1: "one"};
    $rootScope.$emit("Circle Clicked", data);
    $rootScope.$apply();
});

另一件事是你需要确保在使用this关键字时你应该用一些变量在外面声明它然后使用它

控制器

function SquareCtrl($rootScope) {
    var square = this; //made this as a global can be accessible through `square` variable 
    square.showSquare = false; //<-- as changed this to square

    $rootScope.$on("Circle Clicked", function(event, data) {
        square.showSquare = true; //<-- as changed this to square
    })

    //....

}

您还必须取消注册 $rootScope 侦听器,否则会导致应用程序中的内存泄漏。.on 监听器的返回值实际上是一个函数,当 $destroy 事件发生时,您可以使用该函数来实现此目的

// Start Custom Events
var cleanApplyEvent = $rootScope.$on('submitChanges', function(event, args) {
    self.applyData(args);
})

// manually unregister rootScope listeners to avoid memory leaks
$scope.$on('$destroy', function(){
    cleanApplyEvent();
})
// End Custom Events

工作Plunkr

笔记

在控制器内部进行 DOM 操作是不好的做法,您应该创建一个指令来执行 DOM 操作,并且应该从那里处理事件

于 2015-08-27T18:54:08.063 回答