score:5

Accepted answer

Gerardo's answer is pointing in the right direction by using Element.classList, but the proposed solution can still be simplified. As it turns out, the classList property already features a .toggle() method, which works as follows:

toggle( String [, force] )
When only one argument is present: Toggle class value; i.e., if class exists then remove it and return false, if not, then add it and return true. When a second argument is present: If the second argument evaluates to true, add specified class value, and if it evaluates to false, remove it.

Your function can thus be written as:

function toggleLinksActivity(d) {
  d3.selectAll(".link")
    .each(function(l) {
      if (l.target == d) {
        this.classList.toggle("non-active");
      }
    });
}

score:2

Instead of using the D3 classed method again inside itself we can use classList, toggling the class with a more short and elegant function that uses the unary negation and contains to check if the selection has a given class.

In my proposed function, you have to pass the selection and the name of the class. It's just this:

function toggleClass(selection, className) {
    selection.classed(className, !selection.node().classList.contains(className))
}

Explanation

The logic behind this function is quite simple: contains() returns a boolean... so, negating it (!true gives us false and !false gives us true) and passing that negated boolean to the classed method toggles the class in the selection.

Let's see it in action:

var paragraphs = d3.selectAll("p");

d3.interval(function() {
  toggleClass(paragraphs, "foo");
  console.log(paragraphs.attr("class"))
}, 1000)

function toggleClass(selection, className) {
  selection.classed(className, !selection.node().classList.contains(className))
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<p class="foo someOtherClass">Foo</p>
<p class="foo someOtherClass">Bar</p>
<p class="foo someOtherClass">Baz</p>

score:4

You need to reselect the ith element and use its classed property:

function toggleLinkActive() {
  d3.selectAll(".link")
    .classed("non-active", (d,i,nodes) => !d3.select(nodes[i]).classed("non-active"));
}

You can also select this if you are using a non-arrow function:

function toggleLinkActive() {
  d3.selectAll(".link")
    .classed("non-active", function() { return !d3.select(this).classed("non-active"); });
}

If you want to avoid reselecting the item, you can use each and store the selection in a variable:

function toggleLinkActive() {
  d3.selectAll(".link")
    .each(function() {
      const item = d3.select(this);
      item.classed("non-active", !item.classed("non-active"));
    });

Or you can use the native this.classList.toggle("non-active") like in @altocumulus' answer.


Related Query

More Query from same tag