d3 / d3-selection

Transform the DOM by selecting elements and joining to data.

Home Page:https://d3js.org/d3-selection

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Chaining select has a side-effect on data

HyroVitalyProtago opened this issue · comments

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>

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...