As readers might gather from the following...I am fairly new to D3....I am experimenting at the moment using .enter() and .exit().remove(). I am
The key function explains how to join the data to the elements. The default key function if you don't supply one is to use the index.
To understand all this, consider that a d3 selectAll/data is performing two phases of matching. The first is the selector, e.g. d3.selectAll('div'), which will match all divs. The second is the data join, data([1,2,3]), which is looking for elements with data properties which match the data you pass in. The emphasis is because I think understanding this is fundamental to getting full benefit from d3.
Here's an example (also a fiddle) that demonstrates the difference.
function id (d) { return d; }
d3.select('.no-key').selectAll('div')
.data([1,2,3])
.enter().append('div')
.text(id);
d3.select('.yes-key').selectAll('div')
.data([1,2,3], id)
.enter().append('div')
.text(id);
already here
already here
I applaud the efforts of the other answer, but this answer doesn't require parsing a console out, it shows the actual difference in functionality.
Why does this difference happen? Here are the gory details:
If you do a d3.selectAll('div') you are selecting all divs. If you then do a .data([1,2,3]), you are joining that data to those divs: but the join doesn't have a key function, so it isn't looking to see if the divs have [1,2,3] as data elements, it's just going to use the first 3 divs that it finds.
If you instead do .data([1,2,3], function(d){return d;}), your key function says to match [1,2,3] against the data in the divs, so unless you have existing divs that have data elements, you won't match any existing divs.
The illustration of all this is in the .enter().append('div'), which of course adds any necessary divs that weren't found in the above matches. That's the bottom line of all this enter().append business: It adds (number of data elements) - (number of existing elements that match the key function)
Hope this helps!