Angular 6中D3.js树形图点击展开/收缩功能报错排查
this.update is not a function的解决方案 我之前也碰到过完全一样的问题!你遇到的这个错误本质是D3事件回调里的this上下文不对——当点击节点时,D3会把this指向触发事件的DOM节点,而不是你的Angular组件实例,所以自然找不到update方法,类里的其他字段也会变成undefined。
下面给你几个直接适配你代码的解决办法:
方法1:用箭头函数包裹点击事件回调
在绑定点击事件的nodeEnter代码块里,把原来的this.click改成箭头函数形式,这样就能保留组件的this上下文:
let nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", d => "translate(" + source.y0 + "," + source.x0 + ")") .on("click", (event, d) => this.click(d)); // 这里改为箭头函数包裹
注意D3 v4的事件回调参数顺序是(event, d),第一个是事件对象,第二个是节点数据,要对应正确。
方法2:把click方法定义成箭头函数
直接将组件内的click方法改成箭头函数形式,这样不管怎么调用它,this都会固定指向组件实例:
click = (d) => { if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } this.update(d); }
这种方法更彻底,不用修改事件绑定代码,直接从方法定义层面锁定this的指向。
方法3:用bind强制绑定上下文
如果你习惯用普通函数写法,也可以在绑定事件时用bind把组件的this传进去:
.on("click", this.click.bind(this));
不过这种方法要注意:bind会返回新的函数,后续如果需要解绑事件可能会有麻烦,所以前两种方法更推荐。
问题根源说明
在JavaScript中,普通函数的this指向由调用它的上下文决定。D3触发点击事件时,会把回调函数的this设置为触发事件的DOM元素(也就是节点对应的<g>标签),此时this不再是你的DataDisplayerComponent实例,自然访问不到update方法。而箭头函数不会创建自己的this,它会继承外层作用域的this(也就是组件实例),所以就能正常调用this.update了。
随便选一种方法修改后,点击节点的展开/收缩功能就能正常工作啦!
内容的提问来源于stack exchange,提问作者izb

