Add & remove classes with fewer lines of code - javascript

I'm trying to learn how to shorten my jQuery code. Any suggestions or tips would be awesome:
jQuery(document).ready(function($){
$('#checkout_timeline #timeline-4').click(function() {
if ($('#checkout_timeline #timeline-4').hasClass('active')) {
$('#checkout-payment-container').addClass('cpc-visible');
}
});
$('#checkout_timeline #timeline-1, #checkout_timeline #timeline-2, #checkout_timeline #timeline-3').click(function() {
$('#checkout-payment-container').removeClass('cpc-visible');
});
});
To avoid clutter, please find the working version here:
My JSFiddle Code
I know I can use .show() and .hide() but due to other CSS considerations I want to apply .cpc-visible.

There are a handful of things you can improve here. First, you're over-specifying. Ids are unique. No need to select #checkout_timeline #timeline-4 when just #timeline-4 will do. But why even have ids for each li? You can reference them by number using the :nth-child(n) selector. Or better yet, you've already given them application-specific class names like billing, shipment, and payment. Use those! Let's simplify the original content to:
<ul id="checkout_timeline">
<li class='billing'>Billing</li>
<li class='shipping'>Shipping</li>
<li class='confirm'>Confirm</li>
<li class='payment active'>Payment</li>
</ul>
<div id='checkout-payment-container' class='cpc-visible'>
This is the container to show and hide.
</div>
Notice I left the active class, and indeed further initialized the checkout
div with cpc-visible to mirror the payment-is-active condition. Usually I would keep HTML as simple as possible and put "starting positions" initialization in code. But "in for a penny, in for a pound." If we start with payment active, might as well see that decision through, and start the dependent div in a consistent state.
Now, revised JavaScript:
jQuery(document).ready(function($) {
$('#checkout_timeline li').click(function() {
// make clicked pane active, and the others not
$('#checkout_timeline li').removeClass('active');
$(this).addClass('active');
// show payment container only if payment pane active
var paymentActive = $(this).hasClass('payment');
$('#checkout-payment-container').toggleClass('cpc-visible', paymentActive);
});
});
This code is much less item-specific. It doesn't try to add separate click handlers for different tabs/panes. They all get the same handler, which makes a uniform set of decisions. First, that whichever pane is clicked, make it active and the others not active. It does this by removing all active classes, then putting active on just the currently selected pane. Second, it asks "is the current pane the payment pane?" And it uses the toggleClass API to set the cpc-visible class accordingly. Often such "set class based on a boolean condition" logic is simpler and more reliable than trying to pair appropriate addClass and removeClass calls.
And we're done. Here's a JSFiddle that shows this in action.

Try this : You can user jquery selector with timeline and active class to bind click event handler where you can add required class. Same selector but not having active class to remove class.
This will be useful when you add / remove elements and will be more flexible.
jQuery(document).ready(function($){
$('#checkout_timeline .timeline.active').click(function() {
$('#checkout-payment-container').addClass('cpc-visible');
});
$('#checkout_timeline .timeline:not(.active)').click(function() {
$('#checkout-payment-container').removeClass('cpc-visible');
});
});
JSFIddle

Here is one of the ways, you can shorten this code by using :not(). Also its better to use elements than to reference and get them via JQuery always.
jQuery(document).ready(function($) {
var showHideContainer = $('#checkout-payment-container');
$('#checkout_timeline .timeline.active').click(function() {
showHideContainer.addClass('cpc-visible');
});
$('#checkout_timeline .timeline:not(.payment)').click(function() {
showHideContainer.removeClass('cpc-visible');
});
});

try this code its working fine with fiddle
$('.timeline').click(function() {
if ($(this).hasClass('active') && $(this).attr("id") == "timeline-4")
$('#checkout-payment-container').addClass('cpc-visible');
else
$('#checkout-payment-container').removeClass('cpc-visible');
});

This would of been my approach cause you still have to add/remove the active class between each li.
jQuery(document).ready(function($) {
$('ul li').click(function() {
$('ul li.active').removeClass('active');
$(this).closest('li').addClass('active');
k();
});
var k = (function() {
return $('#timeline-4').hasClass('active') ? $('#checkout-payment-container').addClass('cpc-visible') : $('#checkout-payment-container').removeClass('cpc-visible');
});
});
#checkout-payment-container {
float: left;
display: none;
background: red;
color: white;
height: 300px;
width: 305px;
padding: 5px;
}
ul {
list-style: none;
width: 100%;
padding: 0 0 20px 0px;
}
li {
float: left;
padding: 5px 11px;
margin-right: 5px;
background: gray;
color: white;
cursor: pointer;
}
li.active {
background: black;
}
.cpc-visible {
display: block !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="checkout_timeline">
<li id='timeline-1' class='timeline billing'>Billing</li>
<li id='timeline-2' class='timeline shipping'>Shipping</li>
<li id='timeline-3' class='timeline confirm'>Confirm</li>
<li id='timeline-4' class='timeline payment'>Payment</li>
</ul>
<div id='checkout-payment-container'>
This is the container to show and hide.
</div>

Your code look great, i would have written it the same.
bit sure how much it helps but if you like, you can use inline if like this:
$(document).ready(function(){
$('#B').click(function() { (!$('#B').hasClass('active')) ?
$('#A').addClass('active') : ''; });
$('#C').click(function() { $('#A').removeClass('active'); });
});
Link for a live example:
jsFiddle

Related

jQuery on click, add class but also remove if the class is already present

I have a nav menu that needs to trigger with clicks rather than hovers. When the links are clicked, an .open class would be added to the parent li. If that parent already has the .open class, then it would get removed. It would also be removed if another link is clicked on. So far I can get the class added when clicked and removed when a sibling is clicked, but not removed when it's already .open.
I tried adding a hasClass conditional, but that didn't work either. Seemed like it reruns the function every time it's clicked and therefore ignores the hasClass conditional.
Can anyone provide help? I tried toggleClass, but that didn't work.
$('li a').on('click', function() {
$('li a').parent().removeClass('open');
$(this).parent().addClass('open');
});
ul {
list-style: none;
}
li {
display: inline-block;
padding: 10px;
}
.open {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>
Item 1
</li>
<li>
Item 1
</li>
</ul>
</nav>
To do what you require you can use toggleClass() on the parent li when the element is clicked. To remove the class from all other li elements you can use removeClass() along with not() to exclude the current li. Try this:
$('li a').on('click', function() {
let $li = $(this).parent().toggleClass('open');
$('li').not($li).removeClass('open');
});
ul {
list-style: none;
}
li {
display: inline-block;
padding: 10px;
}
.open {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>
Item 1
</li>
<li>
Item 1
</li>
</ul>
</nav>
You can use
jquery toggleClass() to toggle yellow highlight (.open css class) on click/unclicking the same link.
jquery siblings() to remove .open class on all the other li items.
Below is the link for the demo
https://jsfiddle.net/so1u8hq6/
$('li a').on('click', function() {
$(this).parent().siblings().removeClass('open');
$(this).parent().toggleClass('open');
});
ul {
list-style: none;
}
li {
display: inline-block;
padding: 10px;
}
.open {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>
Item 1
</li>
<li>
Item 2
</li>
<li>
Item 3
</li>
</ul>
</nav>
Late to the party, but, after seeing the provided answers and some of the CSS you use I had to urge with my suggestions:
UX. Avoid styling LI tags in general, or at least set the desired display and move on. Style directly the a tag (with the necessary paddings etc.). You'll not only get less CSS to take care of, but also a larger touch interaction area. Makes no sense to style something yellow if it's not a UI part of something interactable. Also in JS, you don't need to take care about the LI wrappers any more - but only about the actual A Elements.
Don't use common selectors like $('li a') - those might target any LI→A elements in your app. Instead be more specific and use a Class like i.e: .tabs for the parent UL. Both in CSS and JS.
Try to use Event Delegation (in jQuey using the .on() method). Not only it will help you to catch the Event.delegateTarget parent UL where needed, but also the this (the clicked element), but mainly reference all the "group" of a elements enclosed in the common parent. That way you can have as many .tabs in a single page as you like. And yes, thanks to Event delegation you can even add dynamically LI Elements - and your JS will still work as expected.
Since you're using <a href="#"> Anchor elements, instead of (more properly) <button type="button>" Elements, you need to also use Event.preventDefault() in order to prevent the browser its default behavior and that's to follow anchors (scroll the page, navigate, etc...)
Use the selector "a.open" when you want to target and remove the "open" class. By just using "a" (or in other answers on this page - "li") you're uselessly touching elements trying to remove a class that's not there in the first place.
Finally, here's the CSS retouch and the proper jQuery needed for your task:
$(".tabs").on("click", "a", function(ev) {
ev.preventDefault();
$("a.open", ev.delegateTarget).not(this).removeClass("open");
$(this).toggleClass("open");
});
.tabs {
display: flex;
list-style: none;
padding: 0;
}
/* Style your Anchors, not the dummy LI wrappers */
.tabs a { padding: 10px; }
.tabs a.open { background-color: yellow; }
<ul class="tabs">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
To explain the only complicated line:
$(
"a.open", // Target just the ones (if any) of class "open"
ev.delegateTarget // inside the common ".tabs" ancestor
)
.not(this) // ... not the clicked element (since later we'll use .toggleClass on it)
.removeClass("open"); // ... remove that class "open"
the rest is pretty self explanatory.
Further read:
jQuery Event Delegation
jQuery event.delegateTarget
Event.preventDefault
So you only want the yellow background to appear as a signifier of user interaction rather than for the background color to be displayed? Have you tried using the mousedown/mouseup functions instead of .on('click', function(){...}?
I was able to simulate the click event where the color showcases via this method:
$('li a').mousedown(function() {
$('li a').parent().removeClass('open');
$(this).parent().addClass('open');
});
$('li a').mouseup(function() {
$('li a').parent().removeClass('open');
});
ul {
list-style: none;
}
li {
display: inline-block;
padding: 10px;
}
.open {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>
Item 1
</li>
<li>
Item 1
</li>
</ul>
</nav>

How do I make the dropdown menu not being down when you enter the website?

When you enter my website (goerann.com) the dropdown register-box is down by default.
If I click in Register, the register-box toogles it visibility as I want, but it doesn't start hidden by default.
$(document).ready(function() {
$('#signup').click(function() {
$('.signupmenu').slideToggle("fast");
});
});
I want it to only show when you click on it. How can I make this happen?
Here's my jsfiddle (http://jsfiddle.net/bdv2doxr/)
Since you're already using the $(document).ready event, you can hide the menu there:
$(document).ready(function() {
$('.signupmenu').hide();
$('#signup').click(function() {
$('.signupmenu').slideToggle("fast");
});
});
And here is your fiddle updated.
You need to make two changes, both involving the removal of display: block. When you toggle this div, it will make the display block. Therefore, you can initialize it as display: none.
Change this:
<div class="signupmenu" style="display: block;">
to this:
<div class="signupmenu">
And also change this:
.signupmenu {
background-color: #FFF;
display: block;
...
to this:
.signupmenu {
background-color: #FFF;
display: none;
...
Updated fiddle here

Disable a href links in php-javascript

I have 4 links in my page(.phtml file) as follows
<ul id="fileMenu" class="contextMenu">
<li class="add"><a id ="addbtn" href="#add" style="display:none;">Add</a></li>
<li class="download">Download</li>
<li class="rename">Rename</li>
<li class="del">Delete</li>
<li class="copypath">Copypath</li>
</ul>
I want to disable the add,rename and delete links
Just disable it from UI .
User should be able to see it but no click event should be performed(linksshould be grayed out) .
I have used
disable="disabled"
display =none;
but they are not serving the purpose.
Any other way this would work out ?
I would use this CSS to visually disable a link:
.disable {
position: relative;
}
.disable:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
}
.disable a {
color: gray;
cursor: default;
}
Then in order to disable a link you would put a class disable on corresponding li:
<li class="download disable">Download</li>
What it does is basically overlays a link with transparent pseudo element :before.
Another solution could be using pointer-events: none rule but it's not well supported in IE.
Demo: http://jsfiddle.net/LPz2Z/1/
If you are using jQuery, you might want to do this
$(function() {
$('#addbtn').click(function(e) {
e.preventDefault();
//do other stuff when a click happens
});
}
More Information, Stackoverflow Question
i'm not sure it's the best way but it can do the trick ,
if you use
pointer-events: none; in your css
or if you want to call it from javascript:
elem.style.display.pointerEvents = "none";
to disabled interaction with your users.
Use pointer-events:none;
<a style='pointer-events:none;background-color:#CFCFCF;color:#000' href="javascript: void(0)">Delete</a>
There are a few options. With plain old javascript, you can do, for example:
Download
or
Download
With jQuery you can easily disable a lot of links:
Download
Delete
<script>
jQuery(document).ready(function($) {
$('a.disabled').on('click', function(e) {
e.preventDefault();
});
});
</script>
And you can even use CSS!
Download
<style type="text/css">
a.disabled { pointer-events: none; }
</style>
Although, it wouldn't surprise you, IE <= v9 (if I'm correct) doesn't support this... And on most browsers you can't force the browser to use a pointer as a cursor...
All in a fiddle demo!
Even this served the purpose
$("#fileMenu").disableContextMenuItems('#add');
$("#fileMenu").disableContextMenuItems('#rename');
$("#fileMenu").disableContextMenuItems('#delete');
as I am using contextMenu class in my ul list.

During hover on parent element, show child (dropdown nav)

I'm trying to make a stupid horizontal nav bar with a drop-down on some of the items. The way I decided to do it is just by putting the drop-down in a div tag. This is easily changeable, i just don't like to go heavy on the html side.
Basically I just want my drop down to work when you hover over the parent element. Additional css is going to be used to make it pretty and positioned better.
Here's my js:
var dropdown = $('.dropdown');
var parent = dropdown.parent();
$(parent).hover(
function () {
dropdown.css('display', 'block');
}
);
Here's my css:
div.nav {
text-align: center;
}
div.nav > ul > li {
margin-top: 15px;
text-align: center;
font-size: 1.25em;
}
div.nav > ul > li {
display: inline-block;
list-style-type: none;
}
div.nav a {
padding: 1em;
}
div.dropdown {
display: none;
background-color: black;
position: absolute;
}
Here's my html:
<div class="nav">
<ul>
<li>Home</li>
<li>
Sample Game
<div class="dropdown">
About it
<br>
Game
</div>
</li>
<li>TP Solutions</li>
<li>Projects</li>
<li>Contact Me</li>
</ul>
<div class="clear"></div>
You should not be using "parent" as a variable name, as it's a reserved word.
$(document).ready(function() {
var $dropdown = $('.dropdown'),
$parent = $dropdown.parent();
$parent.on("mouseover",
function () {
$dropdown.css('display', 'block');
}
);
$parent.on("mouseout",
function () {
$dropdown.css('display', 'none');
}
);
});
According to the oreder this has to be done:
add a jQuery plugin first
Then add your script
so the order will be like this:
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js'>
</script>
<script>
$(function(){
var dropdown = $('.dropdown');
var parent = dropdown.parent();
$(parent).hover(function () {
dropdown.css('display', 'block');
});
});
</script>
Please try the below code.
$(".nav").on("mouseenter","li",function(){
$(this).find(".dropdown").show();
});
$(".nav").on("mouseleave","li",function(){
$(this).find(".dropdown").hide();
});
In your code " dropdown.parent(); " -> this will refer all the parents which have child dropdown and will show the menu. we need to refer current hover parent. Please check the working example in below link.
http://jsfiddle.net/renjith/wX48f/
There are so many good solutions to use jQuery and CSS to show a drop down menus. So you don't need to reinvent the wheel. Here are some examples that you might be able to find one to fit your need.

How to keep hover attributes while disabling click

So I have this list with some hover effect added through CSS.
HTML:
<li>Current Period
<ul>
<li>2012
<li> a href="#">2011</a> //...you get the point
CSS:
#nav a:hover {
background-color: #fff;
color: #333;
}
When the user hovers over current period a list of children elements appear (2012, 2011... which have children of their own). My problem is that users can click on "Current Period". I have managed to remove the click by adding a class to the anchor like so:
<li>Current Period ....
CSS:
.noclick {
pointer-events: none;
cursor: default;
}
but this of course removes the hover feature. I want to keep the hover effect while making the button un-clickable (I was thinking javascript, but I want a more "direct" solution). I appreciate any help :)
In your click handler test whether the clicked item has that class:
$("#nav a").click(function(e){
if ($(e.target).hasClass("noclick"))
return false;
// your other code here
});
Note that by testing the target element for the event you don't then prevent the clicks on child elements from working.
Or if the "noclick" class is not changed dynamically, i.e., those "noclick" links start out as and will always be "noclick", you could change the selector so that your click handler isn't bound to those particular elements:
$("#nav a").not(".noclick").click(function() { ...
Have you tried?
$('.noclick').unbind('click');
or
$('.noclick').click(function(e){e.preventDefault();});
or
Text
Just change your following line:
<li>Current Period ....
for this one
<li>Current Period ....
and change your following css:
.noclick { pointer-events: none; cursor: default; }
for this one
.noclick { cursor: default; }
that should do what you want.
You can use the noClick class to prevent the default event
('.noclick').on('click' , function(e) {
e.preventDefault();
});
on .noclick class remove pointer-events
.noclick { cursor: default; }
and add js to .noclick element
$('.noclick').each(function() {
var $this = $(this);
$this.hover(function() {
// do something...
});
$this.click(function() {
return false;
});
});

Categories

Resources