Tirkal
Tirkal

Reputation: 43

Selection not updating data

I'm trying to update a data array with D3.js but it's doesn't work.

I've read documentation of D3, and many demos on bl.ocks.org but my issue still persist. I don't understand why. I miss something, but I don't find what is this.

This is my code:

const data = [4, 8, 15, 16, 23, 42]
const data2 = [3, 6, 9, 17, 45]

const button = `<button>Click</button>`
document.querySelector('body').insertAdjacentHTML('afterbegin', button)

const svg = d3.select('body')
.append('svg')

const renderArray = (data) => {
    const group = svg.selectAll('g')
    .data(d => data)

    group.exit().remove()

    group.enter()
        .append('g')
        .merge(group)
        .attr('id', d => d)

    const p = group.selectAll("text")
    .data(d => d)

    p.enter()
        .append("text")
        .merge(p)
        .text((d) => d)

    p.exit().remove()
}

renderArray(data)

document.querySelector('button').addEventListener('click', () => renderArray(data2))

My pen : https://codepen.io/Tirkal/pen/OKOvzN?editors=0010

I expect the update of data array.

Upvotes: 1

Views: 48

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102174

You have two main problems:

First, selections are immutable. Therefore, the merge function here...

group.enter()
    .append('g')
    .merge(group)
    //etc...

... is not going to change group. You have to reassign it:

group = group.enter()
    //etc...

Second, the data function only accepts three things: an array, a function or nothing. That being said, for the texts, it should be:

const p = group.selectAll("text")
    .data(d => [d])
    //array-----^

Even better, since those values are not inner arrays or objects just drop those text selections and append the texts directly.

There are other minor problems, but those two are the most important ones.

Here is the resulting code:

const data = [4, 8, 15, 16, 23, 42]
const data2 = [3, 6, 9, 17, 45]

const button = `<button>Click</button>`
document.querySelector('body').insertAdjacentHTML('afterbegin', button)

const svg = d3.select('body')
  .append('svg')

const renderArray = (data) => {
  let group = svg.selectAll('g')
    .data(data)

  group.exit().remove()

  group = group.enter()
    .append('g')
    .merge(group)
    .attr("transform", (_, i) => "translate(10," + (i * 20) + ")")
    .attr('id', d => d)

  const p = group.selectAll("text")
    .data(d => [d])

  p.enter()
    .append("text")
    .merge(p)
    .text((d) => d)

  p.exit().remove()
}

renderArray(data)

document.querySelector('button').addEventListener('click', () => renderArray(data2))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Upvotes: 2

Related Questions