General update pattern not working as expected with d3.selection

南楼画角 提交于 2019-12-13 15:41:34

问题


I am puzzling over why the following simple update pattern doesn't work. This follows the recommended General Update Pattern , as far as I can see.

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

The paragraphs get created fine, but the text isn't set. However, if I do this:

     //update 2 ... this works as expected
     d3.selectAll("p.test").text(function(d) { return d;});

...everything works fine. The first version has always worked in the past.

Update: I tried using the full d3 library ...

<script src="https://d3js.org/d3.v4.min.js"></script>

... and the first version works again. Do I need more than d3.selection?

To clarify, my past practice has been to define a separate update function that takes the selection as a parameter. Eg, function doUpdate(sel) { sel.text(...);}This is for cases where I expect the data elements to have few changes in size, but many changes in content. Storing the selection as a variable and repeatedly running updates on it has worked well before.


回答1:


So after studying the release notes, it seems this is not going to be backwardly compatible, for some good reasons. First, the short answer:

Replace this:

sel.enter().append("p").classed("test", true);
...
sel.text(function(d) { return d;})     //update block

with this:

var update = sel.enter().append("p").classed("test", true).merge(sel);
...
update.text(function(d) { return d;})    //update block

The reason for this is described in this article (thanks @mbostock) and is a fix for empty selector problems with v3. The point I missed at first was that the enter() block needs to run first so that the merge() block has a populated selection to work on. Which means that the merge() call must come off the end of the enter() block chain.

The format of the change documents sort of hid that, because many examples use chains of function calls. I'm used to splitting the enter/update blocks into separate variables. This aids readability (usually) and means I can farm out the enter/update actions to separate functions - more reusable code that way.

So with that in mind, this doesn't work:

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.

But this works okay

var enter = sel.enter();
enter.append(...);
var update = enter.merge(sel);  //defined after block is populated


来源:https://stackoverflow.com/questions/38905428/general-update-pattern-not-working-as-expected-with-d3-selection

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!