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:
- Set a single event handler on the container
- if not an anchor tag, ignore the event
- otherwise, clear the class name from all anchors
- 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>