I've used previous versions of D3 and coming back at v4 I've encountered I don't quite grasp the new update pattern. I have nested data and I wish to update my visualization with new child nodes, here is a minimum example:
function update(data) {
var rows = d3
.selectAll("div")
.data(data)
.enter()
.append("div")
.classed("row", true)
var cells = rows
.selectAll("div")
.data(function(d) { return d })
cells
.enter()
.append("div")
.classed("cell", true)
.text(function(d) {return d})
}
var arr = [
[1, 2, 3],
[1, 2, 3],
[1, 2, 3]
]
var button = d3.select("body")
.append("button")
.text("update")
.on("click", modifyData);
function modifyData(){
arr.forEach(row => {
row.push(4)
});
update(arr);
}
update(arr);
https://jsfiddle.net/59qnhb8d/
I would expect my viz to update with a column of 4's. Any hints appreciated.
You need to update and MERGE the new divs with the old divs:
function update(data) {
var rows = d3
.selectAll(".row")
.data(data)
rows.exit().remove();
var newRows = rows.enter()
.append("div")
.classed("row", true)
var cells = rows.merge(newRows) //here you tell it to merge new rows with existing rows
.selectAll(".cell")
.data(function(d) { console.log(d); return d })
cells.exit().remove();
var newCells = cells
.enter()
.append("div")
.classed("cell", true)
cells
.merge(newCells)
.text(function(d) {return d})
}
Fiddle here: https://jsfiddle.net/59qnhb8d/31/
A few things have likely changed here is Mike Bostocks General Update Pattern. Here is a fiddle with a working update Fiddle. There are 4 important steps in the update pattern:
1) Binding the new data
2) Removing nodes no longer needed
3) Merging non-removed nodes with the newly created ones
4) Updating nodes.
The change is in the update function, the updated version is below.
I went with the .each method for each row created to have better control over the nesting, and without having to do any modifications to the data object. The .each method uses the same pattern, just on its own nested nodes.
function update(data) {
var rows = d3.select("body").selectAll(".row").data(data); // bind data
rows.exit().remove(); // remove old nodes
rows.enter().append("div") // add new nodes
.classed("row", true)
.merge(rows) // merge new with existing and update all
.each(function(d){
let el = d3.select(this);
let cells = el.selectAll(".cell").data(d); // bind data
cells.exit().remove(); //remove old
cells.enter().append("div") //enter new
.classed("cell", true)
.merge(cells) //merge
.text(d=>d) // set text on all nodes.
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With