I'm trying to figure out how to update nested data in a D3 application where the nesting is greater than 2 levels deep. Let's start out with my code.
Here's the jQuery handler when the page is ready.
$(function () {
var data = createDataSet();
updateD3(data);
setTimeout(function () {
var dataAgain = createDataSet();
updateD3(dataAgain);
}, 5000);
});
Here's the update function.
function updateD3(data) {
var level1 = d3
.select('body')
.selectAll('div.level-1')
.data(data);
// UPDATE existing data.
level1
.text(function (d) { return d.nameLevelOne + '-'; })
.selectAll('div.level-2')
.data(function (d) { return d.valuesLevelOne; })
.text(function (d) { return d.nameLevelTwo + '-'; })
.selectAll('div.level-3')
.data(function (d) { return d.valuesLevelTwo; })
.text(function (d) { return d.nameLevelThree + ' ' + d.count + '-'; });
// CREATE new data.
level1
.enter()
.append('div')
.attr('class', 'level-1')
.text(function (d) { return d.nameLevelOne; })
.selectAll('div')
.data(function (d) { return d.valuesLevelOne; })
.enter()
.append('div')
.attr('class', 'level-2')
.text(function (d) { return d.nameLevelTwo; })
.selectAll('div')
.data(function (d) { return d.valuesLevelTwo; })
.enter()
.append('div')
.attr('class', 'level-3')
.text(function (d) { return d.nameLevelThree + ' ' + d.count; });
// REMOVE deleted data.
level1
.exit()
.selectAll('div')
.transition()
.style('opacity', 0)
.remove();
}
Here's the data creation function, which also documents the structure of the data.
function createDataSet() {
return [
{
nameLevelOne: 'A',
valuesLevelOne: [{
nameLevelTwo: 'AA',
valuesLevelTwo: [
{
nameLevelThree: 'AAA',
count: Math.random() * 100
}
]
}]
},
{
nameLevelOne: 'B',
valuesLevelOne: [{
nameLevelTwo: 'BB',
valuesLevelTwo: [
{
nameLevelThree: 'BBB',
count: Math.random() * 100
}
]
}]
}
];
}
When I run this code in the browser, the first updateD3() call is perfect. It shows this:
A
AA
AAA 24.26636815071106
B
BB
BBB 37.17236865777522
When 5 seconds pass and a new data set is created and passed into another call to updateD3(), the output changes to this:
A-
B-
This is NOT the output I expected. I did not expect any part of the DOM to be destroyed. Essentially, I expected the numbers by AAA and BBB to be updated to new values.
Why is this happening? How do I only update the DOM with the updated data?
I have looked and looked around the Internet for solutions but nearly every example of "nested" data is actually only 2 levels deep, or if the data is more than 2 levels deep the example has no code demonstrating updating data.
Any help is greatly appreciated, especially after around 6 hours of beating my head against the wall over this.
You need to make the selection at each level once instead of multiple times, i.e. something like
var level1 = selection.data(...);
level1.enter()...
level1.exit()...
level1....
var level2 = level1.selectAll(...).data(...);
level2.enter()...
level2.exit()...
level2...
var level3 = level2.selectAll(...).data(...);
// etc
When you're making the selections and binding data multiple times, the selections affect each other and you get wrong elements in the selections.
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