Chaining select has a side-effect on data
HyroVitalyProtago opened this issue · comments
HyroVitalyProtago commented
I know that chaining selection can be removed by using one selection like d3.selectAll('#container .item')
, but it should also works in this case. Moreover, data is lost/changed forever after just a selection and that side-effect should not happen.
<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script type="module">
const data = [1,2,3,4]
d3.select('body')
.selectAll('#container')
.data([0])
.enter()
.append('div')
.attr('id', 'container')
d3.select('#container')
.selectAll('.item')
.data(data)
.enter()
.append('div')
.attr('class', 'item')
.text(d => d)
console.log(d3.select('#container').node().__data__) // EXPECTED: 0
console.log(d3.select('#container .item').node().__data__) // EXPECTED: 1
console.log(d3.select('#container').selectAll('.item').nodes()[0].__data__) // EXPECTED: 1
console.log(d3.select('#container').select('.item').node().__data__) // EXPECTED: 1 // get 0
d3.selectAll('.item').each(data => console.log(data)) // EXPECTED: 1, 2, 3, 4 // get 0, 2, 3, 4
</script>
</body>
</html>
HyroVitalyProtago commented
Ok, so it seems it's a feature:
Thus, select also propagates data from parent to child, whereas selectAll does not (hence the need for a data-join)!
But I think the keyword select
isn't appropriate for this kind of behaviour, I would rather use another function with a more transparent name that reflect the data side-effect...