I build these elements ...
<svg>
<g class="group">
<text class="label">Hello</text>
</g>
<g class="group">
<text class="label">World</text>
</g>
</svg>
... from following data:
[
{ id: 'a', label: 'Hello' },
{ id: 'b', label: 'World' },
]
Once create them, I change the data and run .data()
again. However texts are not updated.
Codes https://jsfiddle.net/ginpei/r7b65fzt/ :
function render (data, container) {
const group = container.selectAll('.group')
.data(data, d => d.id)
const entered = group.enter().append('g')
.attr({
class: 'group'
})
entered.append('text')
.attr({
class: 'label'
})
.attr({ y: (d, i) => 20 + i * 20})
const label = group.selectAll('.label')
.text(d => d.label)
}
At the second time, it looks data bound to .group
is updated but data bound to .label
is not. I expected that data would be set as well as the first time.
How to update them?
Actually I found it works if I add .data()
for child elements.
const label = container.selectAll('.label')
.data(data, d => d.id) // <--- added
.text(d => d.label)
Is this the correct way to update them?
It would be great to update them by easier way because my actual codes have a lot of descendant elements.
The solution here is quite simple: just change selectAll
to select
.
const label = group.select('.label')
.text(d => d.label);
To understand why, here is a table I've made with the differences between select
and selectAll
:
Method | select() | selectAll() |
---|---|---|
Selection | selects the first element that matches the selector string | selects all elements that match the selector string |
Grouping | Does not affect grouping | Affects grouping |
Data propagation | Propagates data | Doesn't propagate data |
Pay attention to the propagates data versus doesn't propagate data .
And here is your code with that change and a setTimeout
to change the data:
// d3.js 3.x const container = d3.select('body').append('svg') function render(data, container) { const group = container.selectAll('.group') .data(data, d => d.id) const entered = group.enter().append('g') .attr({ class: 'group' }) entered.append('text') .attr({ class: 'label' }) .attr({ y: (d, i) => 20 + i * 20 }) const label = group.select('.label') .text(d => d.label); } // first try const data1 = [{ id: 'a', label: 'Hello' }, { id: 'b', label: 'World' }, ] render(data1, container) // update const data2 = [{ id: 'a', label: 'Goodbye' }, { id: 'b', label: 'Universe' }, ] setTimeout(function() { render(data2, container) }, 1000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
PS: Your code won't work with v4 (or v5).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.