I have a larger source file which is rather complex, so for now I am skipping the running example. I will try to create a simple example of the row with the core question and create a complete new example on demand:
let newSelection = parentSelection.selectAll(".myChildren")
.data(changedData,d => baseData.id + "/" + d.id);
The idea is that newData is calculated from an array in baseData. The code might get (1) modifications to existing data or (2) complete new baseData objects. It should (1) modifiy the relevant HTML nodes only or (2) remove all nodes and replace them. That is why I use the baseData.id in the key function (or, in this case, Lambda expression).
However, it does not work. Changing the baseData (und thus, baseData.id) results in the nodes being reused as long as both old and new data have elements with identical element id. I.E., the enter selection has a size of 0 or at least too small, while newSelection contains up to all elements. I looked at the D3.js source code and it goes:
for (i = 0; i < dataLength; ++i) {
keyValue = key.call(parent, data[i], i, data) + "";
if (node = nodeByKeyValue.get(keyValue)) {
update[i] = node;
node.__data__ = data[i];
nodeByKeyValue.delete(keyValue);
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
key is the function it gets from the outside call. As this is a closure, it takes the baseData.id from the time of its creation. Thus, my observation above seems to be justified by theory. I could actually solve my problem by using a bit more memory and storing the full key when calculating changedData.
Still, two questions remain: