我很困惑为什么以下简单的更新模式不起作用。据我所知,这遵循推荐的General Update Pattern。
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
...
var dat = ["One","Two","Buckle my shoe"];
var sel = d3.selectAll("p.test").data(dat);
sel.enter().append("p").classed("test", true);
sel.exit().remove();
//update 1 ... doesn't work
sel.text(function(d) { return d;})
这些段落创建得很好,但文本没有设置。但是,如果我这样做:
//update 2 ... this works as expected
d3.selectAll("p.test").text(function(d) { return d;});
......一切正常。第一个版本过去一直在使用。
更新:我尝试使用完整的d3库...
<script src="https://d3js.org/d3.v4.min.js"></script>
...并且第一个版本再次起作用。我需要的不仅仅是d3.selection吗?
为了澄清,我过去的做法是定义一个单独的更新函数,将选择作为参数。例如,function doUpdate(sel) { sel.text(...);}
这是针对我希望数据元素在大小中进行少量更改但内容中的许多更改的情况。将选择存储为变量并在其上重复运行更新之前一直运行良好。
答案 0 :(得分:4)
因此,在研究了发行说明之后,由于某些充分的理由,它似乎不会向后兼容。首先,简短回答:
替换它:
sel.enter().append("p").classed("test", true);
...
sel.text(function(d) { return d;}) //update block
用这个:
var update = sel.enter().append("p").classed("test", true).merge(sel);
...
update.text(function(d) { return d;}) //update block
对此进行了描述in this article(感谢@mbostock)并修复了v3的空选择器问题。我最初错过的一点是,enter()块需要先运行,以便merge()块有一个填充的选择来处理。这意味着merge()调用必须在enter()块链的末尾。
更改文档的格式有点隐藏,因为许多示例使用函数调用链。我曾经习惯将输入/更新块拆分成单独的变量。这有助于提高可读性(通常),这意味着我可以将输入/更新操作分配出来以分离函数 - 这样可以使用更多可重用的代码。
因此,考虑到这一点,没有工作:
var enter = sel.enter();
var update = enter.merge(sel); //Nope! Not populated at this point.
enter.append(...); //too late! Update block uses an empty selection.
但是这没关系
var enter = sel.enter();
enter.append(...);
var update = enter.merge(sel); //defined after block is populated