javascript - 如何通过 D3 单击事件让 $rootScope.$emit() 和 ng-show 协同工作?

标签 javascript angularjs events d3.js angularjs-digest

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

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

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

这是为什么?

我创建了一个小插件来说明我正在尝试做什么。 http://plnkr.co/edit/FnqeAF9kVXxdUdOzT5to .

Controller 代码如下:

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]);

最佳答案

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

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

代码

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

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

Controller

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

Working Plunkr

Note

Its bad practice to have DOM manipulation inside controller, you should create a directive an do DOM manipulation and events should be handle from there

关于javascript - 如何通过 D3 单击事件让 $rootScope.$emit() 和 ng-show 协同工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32257227/

相关文章:

javascript - $(document).ready() 是在主线程中执行,还是异步?

c# - 双击 WPF 形状事件

javascript - 更多 Javascript 状态图框架

javascript - 动态添加 li 到 ul javascript

WPF ListBox OnScroll事件

javascript - 考虑将事件处理程序标记为 'passive' 以使页面更具响应性

javascript - 如何对齐正文中的 div 以保持特定的高度和宽度

javascript - Angularjs $routeParams 导致 RangeError : Maximum call stack size exceeded

javascript - 如何根据选择标签的选定选项的值向变量分配新值,检索并使用变量的新值?

javascript - 没有显示任何内容来代替 AngularJS 表达式