selection.select and data inheritance.
See original GitHub issueI’m hesitant to open this as an issue because I know the behaviour of having selection.select
inherit data from corresponding nodes in the parent selection is totally deliberate. But I think it’s at least worth discussing so here goes.
This side effect of select
is something that confused me when I was first starting out with d3. And I regularly find myself explaining the behaviour to colleagues who are surprised by it. These explanations never seems to stop at the “what happens” but invariably continue into queries of “why would it do that”? I take this repeating pattern as a red flag that there is a rough edge in the API.
I think the confusion stems from 2 points:
- The term
select
has strong connotations of being read-only from popular usage in SQL and other query languages. This seems to run pretty deep for people (myself included). - All other instances of
select
andselectAll
in d3 besidesselection.select
are read only.
I understand that changing this would be a pretty severe backward compatibility break, but just as a thought experiment, do you see any other issues with the following?:
- Make all
select/selectAll
operations to be read only only. - Introduce
selection.update(selector)
to handle the update workflow where you truly do want to propagate data across nodes. This would essentially work just likeselection.select
does today.
It’s maybe not as seamless but there is something nice (to me) about having mutating operations be explicit even if it means sacrificing some convenience.
BTW, I posted a StackOverflow question a little while ago, but that was more targeted at techniques for working around practical issues we were hitting. It adds some relevant context to this topic, though, so here’s a link.
Issue Analytics
- State:
- Created 10 years ago
- Comments:9 (4 by maintainers)
Not a great answer, but one way you can prevent data inheritance is to have an intermediate node without bound data.
Then, any select from the intermediary wouldn’t propagate data from the parent selection. But of course, the intermediate node in the DOM is somewhat unfortunate.
In the d3-graphviz library there is never a 1-to-1 relationship between parents and children and it is never the case that the parent and child are bound to the same data. Thus the propagation of data is never desired.
Since the application where I use d3-graphviz frequently wants to access nodes and edges of the generated graph without affecting bound data, I’ve added an extension to d3-selection, selection.selectWithoutDataPropagation which does
d3.select(this.node().querySelector(name))
I also added a note to the library documentation to avoid the use of selection.select when building applications with d3-graphviz in order to avoid propagating incorrect data by mistake.
Would you we willing to accept a PR to d3-selection adding this function? If so, would you prefer a different name, e.g selectPure?
Even if this function is simple enough to implement outside d3-selection, its pure existence would further highlight that selection.select does more than just pure selection.