Reputation: 8609
This is a strange case when the datum()
function of D3 without param, which is a get function, spoils the value bound to element.
JS Bin link:
https://jsbin.com/jokarapovi/edit?html,js,console
HTML:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
</head>
<body>
<svg id="s">
<g id="g"></g>
</svg>
</body>
</html>
JavaScript:
var log = console.log;
d3.select("#s").datum(1);
d3.select("#g").datum(2);
var s = d3.select("#s");
var g = d3.select("#g");
log("svg datum:",s.datum());
log("g datum:",g.datum());
// This line is a 'get' but it spoils the value
var temp = s.select("#g").datum();
// Wrong value:
log("g datum:",d3.select("#g").datum());
And this is the spoilt output:
"svg datum:" 1
"g datum:" 2
"g datum:" 1
Why should a get function (D3 datum()
without param) spoil the value bound to element?
Upvotes: 1
Views: 36
Reputation: 38201
The behavior you see is an outcome of selection.select()
, we can remove .datum()
from the get line you have and the outcome is the same:
var log = console.log;
d3.select("#s").datum(1);
d3.select("#g").datum(2);
var s = d3.select("#s");
var g = d3.select("#g");
log("svg datum:",s.datum());
log("g datum:",g.datum());
// This get is a 'get' but it spoils the value
var temp = s.select("#g")//.datum();
// Wrong value:
log("g datum:",d3.select("#g").datum());
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
</head>
<body>
<svg id="s">
<g id="g"></g>
</svg>
</body>
</html>
This is because selection.select
binds data bound to selection
to the selected child element (overwriting the previous datum): "If the current element has associated data, this data is propagated to the corresponding selected element." (docs)
This is generally ideal in D3, a one to one parent child relationship generally has the same datum for both parent and child.
If you don't want to pass the parent's datum to the child, the simplest method would be to store a reference to the child or use an identifier that allows it to be selected directly, avoiding the issue:
var log = console.log;
d3.select("#s").datum(1);
d3.select("#g").datum(2);
var s = d3.select("#s");
var g = d3.select("#g");
log("svg datum:",s.datum());
log("g datum:",g.datum());
// This get is a 'get' but it spoils the value
var temp = d3.select("#g").datum();
// Wrong value:
log("g datum:",d3.select("#g").datum());
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
</head>
<body>
<svg id="s">
<g id="g"></g>
</svg>
</body>
</html>
Upvotes: 1