Home > Back-end >  Javascript add class to multiple elements except one
Javascript add class to multiple elements except one

Time:10-31

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>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

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>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

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>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

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>
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

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

document.querySelectorAll('a.link-ranking').forEach((aLink,_,arr)=>{
  aLink.onclick =()=>{
    aLink.classList.add('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>
<iframe name="sif5" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related