🏠 back to Observable

D3 join breaks if run a second time

I’m still trying to understand the .join of d3. I have this notebook that works fine 1st time, but for I run the dis cell a second time, it freaks out.

  const text = d3.select('#radar_text')             
    .selectAll('div')
      .data(quadrants)
    .join('div')
      .attr('id',d => d)
      .html(d => `<h3 style="background-color:Tomato;">${d}</h3>`);

Any help welcome.

On the first run there are no divs inside the container, and join creates a div for each datum; but then the code adds others divs as children of those divs. On the second run, the selectAll(“div”) doesn’t discriminate between the div you have joined and their children, and it doesn’t go well.

To fix the issue you could selectAll(".thing") and add a “thing” class on the divs you join. You’ll then have another issue to fix, which is that the code will still want to add the same contents to divs that already have contents.

1 Like

I’m not sure how to correctly do the selection so it only joins the data once.
Adding a class would not be cool as it would add duplicates…

I think join is an update from using the ‘enter update exit’ pattern, am I wrong in this thinking?

I don’t get this when working with SVG.

Yes, join is a simplification of the enter update exit pattern.

Another way to fix this issue might be to replace selectAll by selectChildren, so you don’t select any divs below the first level:

text = d3
    .select("#rtext") // should all be visabley none
    .selectChildren("div") // <= instead of selectAll
    .data(BS)
    .join("div")
2 Likes

Thanks @Fil that works perfectly.