Unfortunately, you cannot pass a function to classed()
the way you want (i.e., as the first argument). The documentation is clear about classed()
:
selection.classed(names[, value])
If a value is specified, assigns or unassigns the specified CSS class names on the selected elements by setting the class attribute or modifying the classList property and returns this selection. The specified names is a string of space-separated class names. (emphasis mine)
Thus, you cannot pass a function to the class name. The class name there has to be fixed.
That being said, what you're doing right now to add a class name without overwriting a previously existing class...
selection.attr("class", (d) => d3.select(this).attr("class") + " node" + d.id);
... seems to be the standard way among D3 coders, even if you feel that it's a hack. However, you need a small modification here: don't use this
with an arrow function, it's not going to work (check this example d3 v4 retrieve drag DOM target from drag callback when `this` is not available). Thus, this is the correct snippet:
selection.attr("class", function (d){
d3.select(this).attr("class") + " node" + d.id);
});
Yet, it is possible to use classed()
the way you want, not directly (again, you cannot pass a function to it), but in a odd workaround. Just to show you a way to do it using classed()
, I created a demo code that is way more hackish than your solution, for the sake of curiosity. Have a look at it:
var data = [{name: "foo"},
{name: "bar"},
{name: "baz"}];
var body = d3.select("body");
var divs = body.selectAll("myDivs")
.data(data)
.enter()
.append("div")
.attr("class", "someClass");
//here comes the hack:
divs.each(function(d) {
d3.select(this).classed("node" + d.name, () => d3.select(this).datum().name == d.name)
});
//log the classes, you can see the previous class ("someClass") was not overwritten:
divs.each(function() {
console.log(d3.select(this).attr("class"))
})
<script src="https://d3js.org/d3.v4.min.js"></script>
As d.name
is provided by the each()
function, the first argument ("node" + d.name
) is in fact a string.