0

Beginning with JavaScript, I wrote a little script that adds a class to an element on click, and then removes this class if, and only if, another element is click.

I am trying to respect DRY, so I know I should write a function instead to avoid repeating the code such as :

function ToggleClass(element) {
  if (FacebookConst.classList.contains("link-ranking-active") || GoogleConst.classList.contains("link-ranking-active") || ComparisonConst.classList.contains("link-ranking-active") {
  //remove "link-ranking-active" class to all constants **BUT** of element    
  };  
};

but I don’t know the syntax.

Here is my code:

const GoogleConst = document.getElementById('Google');
const FacebookConst = document.getElementById('Facebook');
const ComparisonConst = document.getElementById('Comparison');

const Page = document.getElementById("result");

GoogleConst.addEventListener("click", e => {
    GoogleConst.classList.add("link-ranking-active");
    if (FacebookConst.classList.contains("link-ranking-active") || ComparisonConst.classList.contains("link-ranking-active")) {
      FacebookConst.classList.remove("link-ranking-active");
      ComparisonConst.classList.remove("link-ranking-active");
    };
});

FacebookConst.addEventListener("click", e => {
    FacebookConst.classList.add("link-ranking-active");
    if (GoogleConst.classList.contains("link-ranking-active") || ComparisonConst.classList.contains("link-ranking-active")) {
      GoogleConst.classList.remove("link-ranking-active");
      ComparisonConst.classList.remove("link-ranking-active");
    };
});

ComparisonConst.addEventListener("click", e => {
    ComparisonConst.classList.add("link-ranking-active");
    if (FacebookConst.classList.contains("link-ranking-active") || GoogleConst.classList.contains("link-ranking-active")) {
      FacebookConst.classList.remove("link-ranking-active");
      GoogleConst.classList.remove("link-ranking-active");
    };
});
.link-ranking-active{
  box-sizing: border-box;
  position:relative;
  padding: 0.3em;
  height: 100%;
  width: 100%;
  border-radius: 0.3em;
  border: 0.15em solid #48ffd5;
}
<div class="page">
    <div class="ranking" id="ranking">
      <ul class="ul-menu">
        <li class="li-menu"><a class="link-ranking" id="Google" href="#key">Google</a></li>
        <li class="li-menu"><a class="link-ranking" id="Facebook" href="#key">Facebook</a></li>
        <li class="li-menu"><a class="link-ranking" id="Comparison" href="#key">Comparison</a></li>
      </ul>
    </div>
</div>

3 Answers 3

1

a classic...

goods to knows =
1- classList.toggle() return a Boolean value
2- classList.toggle( CLASSname, Force ) use a force to set the class

document
 .querySelectorAll('a.link-ranking')
 .forEach((aLink,_,arr)=>{
  aLink.onclick =()=>{
    if ( aLink.classList.toggle('link-ranking-active')) {
      arr.forEach(a=>a.classList.toggle('link-ranking-active',aLink===a))
    }}
  })
.link-ranking-active {
  box-sizing    : border-box;
  position      : relative;
  padding       : 0.3em;
  height        : 100%;
  width         : 100%;
  border-radius : 0.3em;
  border        : 0.15em solid #48ffd5;
  }
ul.ul-menu li {
  margin : 1em ;
  }
<div class="page">
  <div class="ranking" id="ranking">
    <ul class="ul-menu">
      <li class="li-menu"><a class="link-ranking" id="Google" href="#key">Google</a></li>
      <li class="li-menu"><a class="link-ranking" id="Facebook" href="#key">Facebook</a></li>
      <li class="li-menu"><a class="link-ranking" id="Comparison" href="#key">Comparison</a></li>
    </ul>
  </div>
</div>

If you didn't want to remove the class on a second click:

document.querySelectorAll('a.link-ranking').forEach((aLink,_,arr)=>{
  aLink.onclick =()=>{
    arr.forEach(a=>a.classList.toggle('link-ranking-active',aLink===a))
  }})
.link-ranking-active {
  box-sizing    : border-box;
  position      : relative;
  padding       : 0.3em;
  height        : 100%;
  width         : 100%;
  border-radius : 0.3em;
  border        : 0.15em solid #48ffd5;
  }
ul.ul-menu li {
  margin : 1em ;
  }
<div class="page">
  <div class="ranking" id="ranking">
    <ul class="ul-menu">
      <li class="li-menu"><a class="link-ranking" id="Google" href="#key">Google</a></li>
      <li class="li-menu"><a class="link-ranking" id="Facebook" href="#key">Facebook</a></li>
      <li class="li-menu"><a class="link-ranking" id="Comparison" href="#key">Comparison</a></li>
    </ul>
  </div>
</div>

Sign up to request clarification or add additional context in comments.

Comments

1

The technique to use here is called Event Delegation. Here is how this works:

  1. Set a single event handler on the container
  2. if not an anchor tag, ignore the event
  3. otherwise, clear the class name from all anchors
  4. finally, apply the class name to the target of the event (the one that got clicked).

const container = document.querySelector('.ul-menu');
const anchors = document.querySelectorAll('.ul-menu li a');

container.addEventListener('click', (e) => {
  if (e.target.nodeName !== "A") return;
  anchors.forEach(anchor => {
    anchor.classList.remove('link-ranking-active');
  });
  e.target.classList.add('link-ranking-active');

});
.link-ranking-active {
  box-sizing: border-box;
  position: relative;
  padding: 0.3em;
  height: 100%;
  width: 100%;
  border-radius: 0.3em;
  border: 0.15em solid #48ffd5;
}
<div class="page">
  <div class="ranking" id="ranking">
    <ul class="ul-menu">
      <li class="li-menu"><a class="link-ranking" id="Google" href="#key">Google</a></li>
      <li class="li-menu"><a class="link-ranking" id="Facebook" href="#key">Facebook</a></li>
      <li class="li-menu"><a class="link-ranking" id="Comparison" href="#key">Comparison</a></li>
    </ul>
  </div>
</div>

2 Comments

Thank you for your answer. However, for the sake of learning, I am not sure what this line does: if (e.target.nodeName !== "A") return; anchors.forEach(anchor =>
That code refers to step 2 in my answer. If the node (HTML element) is not and Anchor (<a>) then simply do nothing by returning (exiting) the function. Unlike the other answers that add an event handlers for each anchor tag, only one is needed. Events bubbling is a tool to use in your case. It allows a single event handler to handle 'click' events in this caes with a single function. Short and sweet. You can always switch you accepted answer to this one if you find it helpful. The article I linked in the answer provides a lot of explanation for you. Have fun!
1

Good on you for realizing you should clean this up. The code should be fairly self explanatory once you see it.

const elements = ['Google', 'Facebook', 'Comparison'].map(id => document.getElementById(id))

const eventHandler = (e => {
  elements.map(element => element.classList.remove("link-ranking-active"))
  e.target.classList.add("link-ranking-active")
})

elements.forEach(element => element.addEventListener("click", eventHandler))
.link-ranking-active {
  box-sizing: border-box;
  position: relative;
  padding: 0.3em;
  height: 100%;
  width: 100%;
  border-radius: 0.3em;
  border: 0.15em solid #48ffd5;
}
<div class="page">
  <div class="ranking" id="ranking">
    <ul class="ul-menu">
      <li class="li-menu"><a class="link-ranking" id="Google" href="#key">Google</a></li>
      <li class="li-menu"><a class="link-ranking" id="Facebook" href="#key">Facebook</a></li>
      <li class="li-menu"><a class="link-ranking" id="Comparison" href="#key">Comparison</a></li>
    </ul>
  </div>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.