Matt Leonowicz
Matt Leonowicz

Reputation: 583

D3.js and nested data - Why is my exit() set empty

I'm having an issue when dealing with manipulating nested data with D3.js

Data consists of array of objects which represent categories. Each category has multiple checkins. I want a section for every category, and within that, a div for each checkin. I manipulate data over time and rely on update, enter and exit mechanisms of D3.js to properly output the data to DOM.

What I don't understand:

The second problem is probably related to the first one, but now I'm not sure.

Here's an interactive bl.ocks.org: https://bl.ocks.org/mattleonowicz/fd975a6d914f90c9934464df57e498c9

Same code below:

<html>
<body>
<div id="app" /> 
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
  const data1 = [
  {
    category: {
      id: 1
    },
    checkins: [
      {
        lat: 1,
        lon: 1
      },
      {
        lat: 2,
        lon: 2
      }
      // ... more objects like this would normally be here
    ]
  }
  // ... more objects like this would normally be here
];
const data2 = [
  {
    category: {
      id: 1
    },
    checkins: [
      {
        lat: 3,
        lon: 3
      },
      {
        lat: 4,
        lon: 4
      }
      // ... more objects like this would normally be here
    ]
  }
  // ... more objects like this would normally be here
];

update(data1);
setTimeout(() => update(data2), 2000);
setTimeout(() => update(data1), 4000);

function update(data) {
  const categoriesData = d3.select('#app')
    .selectAll('section')
    .data(data, d => d.category.id);

  // CATEGORIES EXIT
  categoriesData.exit()
    .remove();

  // CATEGORIES UPDATE + ENTER - bind all categories with their checkins
  const checkinsData = categoriesData.enter()
    .append('section')
    .merge(categoriesData)
    .selectAll('section')
    .data(d => d.checkins, d => `${d.lon},${d.lat}`);

  // CHECKINS UPDATE : nothing, because checkins will only come and go

  // CHECKINS EXIT
  checkinsData.exit()
    .remove();

  // CHECKINS ENTER
  checkinsData.enter()
    .append('div')
    .html(d => `${d.lon},${d.lat}`);
}
</script>
</body>
</html>

Upvotes: 2

Views: 538

Answers (1)

Yaroslav Sergienko
Yaroslav Sergienko

Reputation: 720

You have a typo here:

  // CATEGORIES UPDATE + ENTER - bind all categories with their checkins
  const checkinsData = categoriesData.enter()
    .append('section')
    .merge(categoriesData)
->  .selectAll('section')
    .data(d => d.checkins, d => `${d.lon},${d.lat}`);

You wanted to write .selectAll('div') in the second selection.

Upvotes: 3

Related Questions