CSS - better way to remove class in this case? - javascript

I have a menu of 5 items. When I click any item, I add a class to change color on it. I also remove the color from the other 4 items, whether they have color or not. Is there a better way, perhaps through CSS, to remove those classes that aren't selected?
switch(currentC.data("template")) {
case "cataction1": {
currentC.addClass( "active cataction1Current" );
$( ".catbarlist li" ).not( currentC ).removeClass( "cataction2Current cataction3Current cataction4Current cataction5Current active activenotransit" );
break;
}
case "cataction2": {
currentC.addClass( "active cataction2Current" );
$( ".catbarlist li" ).not( currentC ).removeClass( "cataction1Current cataction3Current cataction4Current cataction5Current active activenotransit" );
break;
}
case "cataction3": {
currentC.addClass( "active cataction3Current" );
$( ".catbarlist li" ).not( currentC ).removeClass( "cataction1Current cataction2Current cataction4Current cataction5Current active activenotransit" );
break;
}
case "cataction4": {
currentC.addClass( "active cataction4Current" );
$( ".catbarlist li" ).not( currentC ).removeClass( "cataction1Current cataction2Current cataction3Current cataction5Current active activenotransit" );
break;
}
case "cataction5": {
currentC.addClass( "active cataction5Current" );
$( ".catbarlist li" ).not( currentC ).removeClass( "cataction1Current cataction2Current cataction3Current cataction4Current active activenotransit" );
break;
}
}

Drop using a unique class for each item and use a single common class for marking current item.
For example, with jQuery:
$(document).on('click', '.my-menu > LI', function() {
// Unmarking previously marked item.
$(this.parentNode).children('.cur').removeClass('cur');
// Marking new current item.
$(this).addClass('cur');
});

Example menu:
<li class="menu-item">
About
Home
</li>
Add the following CSS:
.menu-item .active{
background-color:#1B3E70;
color:white;
}
Then with jquery:
$('.menu-item a').click(function(){
$(this).addClass('active').siblings().removeClass('active');
});

Other solution might be:
$(document).on("click", ".catbarlist li", function(e){
$(this).addClass('active');
$(this).siblings('.active').removeClass('active');
});

I assume all those classes are necessary (as you have an .active class already). I also assume there's a good reason you're not using a click event.
If so, the first thing you could do is make it a lot cleaner/easier on yourself by creating a function to remove the unwanted styles. Lots of repeating code is not good -- hard to read, hard to maintain. For example:
function removeCatbarColor() {
$(".catbarlist li").removeClass("cataction1Current cataction2Current
cataction3Current cataction4Current cataction5Current active activenotransit");
}
And then calling it before applying the style to the active one:
switch(currentC.data("template")) {
case "cataction1": {
removeCatbarColor();
currentC.addClass( "active cataction1Current" );
break;
}
case "cataction2": {
removeCatbarColor();
currentC.addClass( "active cataction2Current" );
break;
}
...
There could probably be further improvements, but without seeing your HTML/CSS I can only guess. (Do you really need so many classes? A working JSFiddle would really help.)
A better way of handling things, given your description below, would be to have permanent classes for each cataction. So something like:
<ul>
<li class="cataction1">Link</li>
<li class="cataction2">Link</li>
<li class="cataction3">Link</li>
<li class="cataction4">Link</li>
</ul>
That way all you need in your CSS is:
.cataction1 {
// styles when not active
}
.cataction1.active {
// styles when active
}
// etc
Which allows you to simplify your JS like so:
$('li').on('click', function() {
$(this).siblings().removeClass('active');
$(this).addClass('active');
});
That is a much better way of handling things.

Related

I have a named function which works great on click. How can I run it on a specific element when the page loads?

So, I have a function called runFilter. It works great when I run it on click. If you look at the line underneath "on load, run the filter," that doesn't work at all. If it was a built-in function like .css() then it would work fine, but this isn't a built-in function and I've already failed at extending jQuery to make it one.
I'm probably doing something very obvious wrong here, but what I want to happen is for the function to fire once after the page is loaded, targeting this specific link: ul > li:first-child a.
jQuery(document).ready(function( $ ) {
function runFilter( event ) {
console.log( this );
event.preventDefault();
//* add active class on the active nav item
$( 'ul.attractions-filters a' ).removeClass( 'active' );
$( this ).addClass( 'active' );
//* add active class for visible things
term = $( this ).attr( 'data-term' );
$( '.type-attractions' ).removeClass( 'active' );
$( '.attractiontype-' + term ).addClass( 'active' );
}
// Show everything once the page is fully loaded
$( '.type-attractions' ).addClass( 'active' );
//* On load, run the filter
// $( 'ul.attractions-filters:first a' ).on( 'load', runFilter );
//* On click, run the filter
$( 'ul.attractions-filters a' ).on( 'click', runFilter );
});
While it's not clear which A of which UL you're actually trying to refer to, there are a bunch of different ways of doing it:
The example below depends on a few things:
jQuery will call any method attached through .on via the .click
method. It automatically binds it to the function.
jQuery will let you invoke known events through the .trigger method. It automatically binds it to the function
querySelector only returns the first element that matches a selector (may be easier to read than the equivalent jQuery selector)
let selector = 'ul.attractions-filters a';
let firstSelector = 'ul.attractions-filters:first a';
let firstChildSelector = 'ul.attractions-filters a:first';
let firstChildSelectorJQ = 'ul.attractions-filters:first a:first';
let whatYouAskedFor = 'ul > li:first-child a'
$(function() {
function runFilter() {
console.log(this)
}
$(selector).on('click', runFilter);
console.log( "This selector will click all A elements in the first UL with class 'attractions-filters'")
$(firstSelector).click();
$(firstSelector).trigger('click');
console.log( "This selector will click the first A element in every UL with class 'attractions-filters'")
$(whatYouAskedFor).click();
$(whatYouAskedFor).trigger('click');
console.log("These selectors will click the first A element in the first UL with class 'attractions-filters'")
$($(firstSelector)[0]).click();
$($(firstSelector)[0]).trigger('click');
$(firstChildSelector).click();
$(firstChildSelector).trigger('click');
runFilter.bind($(firstSelector)[0])();
console.log("These selectors will select only the first child of the first UL of class 'attractions-filters' and click it")
$(firstChildSelectorJQ).click();
$(firstChildSelectorJQ).trigger('click');
runFilter.bind($(firstChildSelectorJQ)[0])();
runFilter.bind(document.querySelector(selector))();
console.log("This selector is the requirement you gave")
runFilter.bind(document.querySelector(whatYouAskedFor))();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>What You Asked For</li>
</ul>
<ul class="attractions-filters">
<li>UL 1, LI 1</li>
<li>UL 1, LI 2</li>
</ul>
<ul class="attractions-filters">
<li>UL 2, LI 1</li>
<li>UL 2, LI 2</li>
</ul>
You're very close!
Your code, modified below, with a few comments:
// altered to be a briefer document ready (Still no-conflict safe!)
jQuery(function( $ ) {
function runFilter( event ) {
event.preventDefault();
// add active class on the active nav item
$( 'ul.attractions-filters a' ).removeClass( 'active' );
$( this ).addClass( 'active' );
// add active class for visible things
term = $( this ).attr( 'data-term' );
$( '.type-attractions' ).removeClass( 'active' );
$( '.attractiontype-' + term ).addClass( 'active' );
}
// Show everything once the page is fully loaded
$( '.type-attractions' ).addClass( 'active' );
// On click, run the filter
$( 'ul.attractions-filters a' ).on( 'click', runFilter );
// NOTE: Choose ONE of the following three methods:
// Method #1: using trigger
$( 'ul.attractions-filters:first a' ).trigger( 'click' );
// Method #2: using click
$( 'ul.attractions-filters:first a' ).click();
// Method #3: better yet "chain" the methods to reduce duplicate code...
// NOTE: this replaces BOTH your .on('click') AND the .trigger or .click above...
$( 'ul.attractions-filters a' )
.on( 'click', runFilter )
.trigger( 'click');
});

JQuery click event and toggleClass method

I created a simple lottery ticket and I made selector with toggle method.
This is my code.
$( "span" ).click(function() {
$( this ).toggleClass( "span-selected" );
});
The toggle functionality works fine but I want to add a limitation so that only 7 numbers can be chosen in one container. Is there a way to achieve this.
Here is my JSBIN > http://jsbin.com/menawu/1/edit?js,output
You need to check if there are already 7 elements checked in that container, like so:
$( "span" ).click(function() {
if (
$(this).hasClass("span-selected") ||
(!$(this).hasClass(".span-selected") && $(this).closest(".num-cont").find(".span-selected").length < 7)
) {
$( this ).toggleClass( "span-selected" );
}
});
So your criteria are:
if it's not selected, check if there are less than 7: if yes, toggle, otherwise don't do anything
if it is selected, unselect it.
You can use this code;
$( "span" ).click(function() {
if($(this).parent().parent().find('.span-selected').length===7){
alert('Limit');
}
else{
$( this ).toggleClass( "span-selected" );
}
});
Yes,
you can cumulate the count of tickets chosen in a variable and allow toggling only when count is less than 7, based on the jQuery hasClass method to check if your span was previously selected:
var countTicket = 0;
$( "span" ).click(function() {
if($(this).hasClass( "span-selected")) {
countTicket--;
$( this ).toggleClass( "span-selected" );
} else if(countTicket<7) {
$( this ).toggleClass( "span-selected" );
countTicket++;
}
});
Here an example, with multiple case for controle your numbers.
You can easily know if it's unselect/select or if more than 7 span are selected by using hasClass/removeClass/addClass
$("span").click(function(){
if($(this).hasClass("selected"))
{
$(this).removeClass("selected");
}
else{
if($("span.selected").length<7)
{
$(this).addClass("selected");
}
else
console.log("7 span selected");
}
});
span{
width:50px;
height:50px;
margin:10px;
background-color:#eee;
display:inline-table;
}
.selected{
background-color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
just insert count and max variables
var max = 7;
var count = 0;
$("span").click(function() {
if (count < max) {
$(this).toggleClass("span-selected");
count++;
}
});
You can get the number of selected item using the parent container and count them:
$( "span" ).click(function() {
if($(this).closest('.num-cont').find('.span-selected').length==7){
alert('Limit');
}
else{
$( this ).toggleClass( "span-selected" );
}
});

How to dismiss dropdown menu in WordPress template on new page

I'm working on a Wordpress template and one of the features is a dropdown menu in the header. You click the arrow to open it, and it remains open until you click the arrow to close it. But, when you click on one of the links, it still remains open on the next page. You have to click the arrow to close it.
I would like the dropdown menu to automatically close when navigating to a new page. Here is my js for the navigation... I'm following a tutorial from Lynda so I didn't write this code, but I haven't had enough experience with js to know which section of the code is doing what exactly.
Please let me know if you need any other information.
function initMainNavigation( container ) {
// Add dropdown toggle that display child menu items.
container.find( '.menu-item-has-children > a' ).after( '<button class="dropdown-toggle" aria-expanded="false">' + screenReaderText.expand + '</button>' );
// Toggle buttons and submenu items with active children menu items.
container.find( '.current-menu-ancestor > button' ).addClass( 'toggle-on' );
container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' );
container.find( '.dropdown-toggle' ).click( function( e ) {
var _this = $( this );
e.preventDefault();
_this.toggleClass( 'toggle-on' );
_this.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
_this.attr( 'aria-expanded', _this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
_this.html( _this.html() === screenReaderText.expand ? screenReaderText.collapse : screenReaderText.expand );
} );
}
initMainNavigation( $( '.main-navigation' ) );
// Re-initialize the main navigation when it is updated, persisting any existing submenu expanded states.
$( document ).on( 'customize-preview-menu-refreshed', function( e, params ) {
if ( 'primary' === params.wpNavMenuArgs.theme_location ) {
initMainNavigation( params.newContainer );
// Re-sync expanded states from oldContainer.
params.oldContainer.find( '.dropdown-toggle.toggle-on' ).each(function() {
var containerId = $( this ).parent().prop( 'id' );
$( params.newContainer ).find( '#' + containerId + ' > .dropdown-toggle' ).triggerHandler( 'click' );
});
}
});
I know that this question is almost a year old, but I wanted to go ahead and post an answer just in case someone needs it in the future.
The following lines from your code are what's causing the toggles to stay open when you go to a new page.
// Toggle buttons and submenu items with active children menu items.
container.find( '.current-menu-ancestor > button' ).addClass( 'toggle-on' );
container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' );
When you navigate to a page that is part of a sub-menu, these lines automatically add the 'toggle-on' class to the appropriate toggle button and parent sub-menu of that page. If you comment out those lines, the sub-menus will close when you navigate to a new page.

Make the collapsible sortable accordion sort in collapse shape

I have accordion is collapsible and sortable.
Look here full code in action http://jsfiddle.net/wvtPw/
And this the JS code I'm using
$( "#accordion" )
.accordion({
header: "> div > h3",
collapsible: true
})
.sortable({
handle: "h3",
placeholder: "ui-state-highlight",
stop: function( event, ui ) {
// IE doesn't register the blur when sorting
// so trigger focusout handlers to remove .ui-state-focus
ui.item.children( "h3" ).triggerHandler( "focusout" );
}
});
The only problem when I'm trying to sort the expanded div group is big and hard to sort and when its the first div and you drag it, you can't see below it because if the height size
See this image below is example of collapsed div, see how easy to use and you can see below it easily.
So what I need to reach is when the user trying to sort expanded div, the flying div turn into collapsed shape like this
And when he drop the element just turn back to expanded like normal
I recommend doing the following:
$(function() {
var active = false,
sorting = false;
$( "#accordion" )
.accordion({
header: "> div > h3",
collapsible: true,
activate: function( event, ui){
//this fixes any problems with sorting if panel was open
//remove to see what I am talking about
if(sorting)
$(this).sortable("refresh");
}
})
.sortable({
handle: "h3",
placeholder: "ui-state-highlight",
start: function( event, ui ){
//change bool to true
sorting=true;
//find what tab is open, false if none
active = $(this).accordion( "option", "active" );
//possibly change animation here (to make the animation instant if you like)
$(this).accordion( "option", "animate", { easing: 'swing', duration: 0 } );
//close tab
$(this).accordion({ active:false });
},
stop: function( event, ui ) {
ui.item.children( "h3" ).triggerHandler( "focusout" );
//possibly change animation here; { } is default value
$(this).accordion( "option", "animate", { } );
//open previously active panel
$(this).accordion( "option", "active", active );
//change bool to false
sorting=false;
}
});
});
DEMO:
http://jsfiddle.net/m939m/2/
Please let me know if you have any questions! Cheers!
have a look at the documentation for sortable
look at the sortable event start( event, ui ). The logic would then check to see if the item is expanded. if so then close it. after sort expand it again
http://api.jqueryui.com/sortable/#event-start
Add the code below before the stop event on your sortable object.
over: function(event, ui) {
$('#accordion').accordion({active:false});
},
http://jsfiddle.net/wvtPw/8/
While this code works for the collapsing/expanding issue when sorting, the "activate"-function causes an issue regarding opening the first item in the accordion. Opening and closing the first item makes it impossible to reopen. Continuing with the next item, same thing happens. In the end the complete list of items will not be possible to expand.
Since this is more of a UX question, my suggestion is to offer a different UX. I would disable sorting by default and offer a button to toggle sorting on/off. When sorting is enabled, collapse all the fields and disable the accordion.
$( '.accordion-toggle' ).on('click', function() {
$( "#accordion" ).toggleClass( 'sorting' );
});
$( "#accordion:not(.sorting)" )
.accordion({
header: "> div > h3",
collapsible: true
});
$( "#accordion.sorting" )
.sortable({
handle: "h3",
placeholder: "ui-state-highlight",
stop: function( event, ui ) {
// IE doesn't register the blur when sorting
// so trigger focusout handlers to remove .ui-state-focus
ui.item.children( "h3" ).triggerHandler( "focusout" );
}
});
EDIT: (2018-06-18)
I missed that this is jQuery UI. You probably want to use the enable/ disable features.
$( '.accordion-toggle' ).on( 'click', function() {
if ( $( '#accordion' ).hasClass( 'sorting' ) ) {
$( '#accordion' ).removeClass( 'sorting' )
.accordion( "enable" )
.sortable( "disable" );
} else {
$( '#accordion' ).addClass( 'sorting' )
.sortable( "enable" )
.accordion( "disable" )

jQuery/javascript - Highlight for a menu when user click on it

Hi
Suppose I have a menu like:
<ul>
<li>notebook</li>
<li>camera</li>
<li>phone</li>
</ul>
When I click on a menu, the menu will be highlighted, if click on another menu, this menu will be highlighted and other menu will return to original(no highlighted). Can someone give me some idea how to do it(create a listener for <li> or anything else)?
Thanks you
The most efficient way would be via .delegate(), like this:
$("ul").delegate("li", "click", function() {
$(this).addClass("active").siblings().removeClass("active");
});
Then just give it some styling to match, for example:
.active a { color: red; }
You can test it out here, if you want a click on an already-active <li> to make it inactive, then change .addClass() to .toggleClass(), like this.
You didn't provide a lot to go on, but assuming that's the only unordered list on the page...
<script type="text/javascript">
$( document ).ready( function() {
$( 'ul li' ).click( function() {
$( 'ul li' ).removeClass( 'highlight' );
$( this ).addClass( 'highlight' );
});
});
</script>
So when any li gets clicked, the 'highlight' class (assuming there is one that does the highlighting of which you speak) gets removed from all of the li elements. Then the one that triggered the click gets the highlight class.
Might be better to have the 'a' element actually trigger the jquery, now that I think about it.
<script type="text/javascript">
$( document ).ready( function() {
$( 'ul li a' ).click( function() {
$( 'ul li' ).removeClass( 'highlight' );
$( this ).parent( 'li' ).addClass( 'highlight' );
});
});
</script>
That's the best I can do given the information that you've provided.

Categories