如何通过 D3 单击事件让 $rootScope.$emit() 和 ng-show 协同工作?
How do I get $rootScope.$emit() and ng-show to work together via a D3 click event?
我在 angular 指令中包装 D3 svg 图像。当用户单击该 D3 图像时,我想在控制器中将变量设置为 true,以便 ng-show 然后显示另一个 D3 图像。
我所做的是向 D3 图像添加一个 .on("click")
函数,并在该函数中使用 $rootScope.$emit()
发送一个事件。在第二张图片的控制器中,我有一个 $rootScope.$on()
来控制事件并将 ng-show 的变量设置为 true。
这种方法行不通。我已经测试了代码以确保事件被正确发出和捕获,但是 ng-show 没有显示第二个 D3 图像。
这是为什么?
我创建了一个小插件来说明我正在尝试做什么。
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]);
从外部 Angular 上下文更改 angular 的范围不会更新范围变量和绑定,因为它不会 运行 Angular.In 的摘要循环正在使用事件 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 监听器的 return 值实际上是你在 $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
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
我在 angular 指令中包装 D3 svg 图像。当用户单击该 D3 图像时,我想在控制器中将变量设置为 true,以便 ng-show 然后显示另一个 D3 图像。
我所做的是向 D3 图像添加一个 .on("click")
函数,并在该函数中使用 $rootScope.$emit()
发送一个事件。在第二张图片的控制器中,我有一个 $rootScope.$on()
来控制事件并将 ng-show 的变量设置为 true。
这种方法行不通。我已经测试了代码以确保事件被正确发出和捕获,但是 ng-show 没有显示第二个 D3 图像。
这是为什么?
我创建了一个小插件来说明我正在尝试做什么。 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]);
从外部 Angular 上下文更改 angular 的范围不会更新范围变量和绑定,因为它不会 运行 Angular.In 的摘要循环正在使用事件 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 监听器的 return 值实际上是你在 $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
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