Switching between three classes with different names - javascript

I have a header and three different classes defines three different sizes. On click of the different buttons I need to apply the size class to the header and remove the existing heading size class.
JS Fiddle
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item"><a id="smallHeader">S</a></li>
<li class="list-inline-item"><a id="mediumHeader">M</a></li>
<li class="list-inline-item"><a id="largeHeader">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>
jQuery:
this.$('.list-inline-item').click(function() {
if ($('.layout-attachments h1').hasClass('w-50-p')) {
$('.layout-attachments h1').removeClass('w-50-p').addClass('w-75-p ');
} else if ($('.layout-attachments h1').hasClass('w-75-p ')) {
$('.layout-attachments h1').removeClass('w-75-p ').addClass('w-100-p');
} else if ($('.layout-attachments h1').hasClass('w-100-p')) {
$('.layout-attachments h1').removeClass('w-100-p').addClass('w-50-p');
}
});
});

This is very easy. Here i made an example.
Make sure to read the comment and also have a look at attribute Size
var sizes= ["w-75-p", "w-100-p", "w-50-p" ]
$('.list-inline-item').click(function() {
sizes.forEach((item)=> $('.layout-attachments h1').removeClass(item) ); // reset the size.
// now Add the right Size
$('.layout-attachments h1').addClass($(this).attr("size"))
});
.w-50-p {
font-size: 18px;
}
.w-75-p {
font-size: 26px;
}
.w-100-p {
font-size: 34px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item" size="w-50-p"><a id="smallHeader">S</a></li>
<li class="list-inline-item" size="w-75-p"><a id="mediumHeader">M</a></li>
<li class="list-inline-item" size="w-100-p"><a id="largeHeader">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>
</div>

There are a couple of issues with your code. For starters, you have a syntax error in your jQuery block. You also don't need spaces after your class names in the removeClass calls. But the biggest issue is you need to be able to determine if the user has clicked "small", "medium", or "large" in order to apply the correct class. Otherwise, if you make the other corrections I mentioned, as it is right now you will basically just be toggling through the three classes.
Here's how I might approach the problem, with click handlers for each of the list elements (small, medium, large):
this.$('.list-inline-item').click(function(e) {
if (e.target.id === "smallHeader") {
// handle small case
$(".layout-attachments h1").removeClass("w-75-p w-100-p").addClass("w-50-p");
} else if (e.target.id === "mediumHeader") {
// handle medium case
$(".layout-attachments h1").removeClass("w-50-p w-100-p").addClass("w-75-p");
} else if (e.target.id === "largeHeader") {
// handle large case
$(".layout-attachments h1").removeClass("w-50-p w-75-p").addClass("w-100-p");
} else {
// unhandled case
}
});
.w-50-p {
font-size: 18px;
}
.w-75-p {
font-size: 26px;
}
.w-100-p {
font-size: 34px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item"><a id="smallHeader">S</a></li>
<li class="list-inline-item"><a id="mediumHeader">M</a></li>
<li class="list-inline-item"><a id="largeHeader">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>
</div>
Another thing you could do, instead of calling removeClass with the other classes you don't want attached to the element, is add a function to jQuery that will remove all classes according to some substring. For example, with this function, you could remove all classes starting with "w-":
$.fn.removeClassStartingWith = function (filter) {
$(this).removeClass(function (index, className) {
return (className.match(new RegExp("\\S*" + filter + "\\S*", 'g')) || []).join(' ')
});
return this;
};
You could invoke it then like this:
$(".layout-attachments h1").removeClassStartingWith("w-").addClass("w-50-p");
This is not absolutely necessary but might be useful.

You had some errors in your jQuery:
$('.list-inline-item').on('click', function() {
if ($('.layout-attachments h1').hasClass('w-50-p')) {
$('.layout-attachments h1').removeClass('w-50-p').addClass('w-75-p');
} else if ($('.layout-attachments h1').hasClass('w-75-p')) {
$('.layout-attachments h1').removeClass('w-75-p ').addClass('w-100-p');
} else if ($('.layout-attachments h1').hasClass('w-100-p')) {
$('.layout-attachments h1').removeClass('w-100-p').addClass('w-50-p');
}
});
But either way the code doesn't make much sense as it is, because it doesn't matter what li item you click.
Edit:
html:
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item" data-size="w-50-p"><a id="smallHeader">S</a></li>
<li class="list-inline-item" data-size="w-75-p"><a id="mediumHeader">M</a></li>
<li class="list-inline-item" data-size="w-100-p"><a id="largeHeader">L</a></li>
</ul>
<h1 id="w-75-p" class="img-responsive img-thumbnail">Change the class of this element</h1>
</div>
</div>
jQuery:
$('.list-inline-item').on('click', function() {
var newSize = $(this).attr("data-size");
$(".layout-attachments h1").removeAttr("id").attr("id", newSize)
});
css:
#w-50-p {font-size: 18px;}
#w-75-p {font-size: 26px;}
#w-100-p {font-size: 34px;}
The easiest was is to use an id on the target element and set a data attribute which refers to the correct id.

You can do this:
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item"><a id="smallHeader" data-new-class="w-50-p">S</a></li>
<li class="list-inline-item"><a id="mediumHeader" class="active" data-new-class="w-75-p">M</a></li>
<li class="list-inline-item"><a id="largeHeader" data-new-class="w-100-p">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>
</div>
there is an class="active" and data-new-class="w-75-p" that track what is currently clicked and what class to apply when click. You can find a better name for the data attribute.
For javascript:
$('.list-inline-item a').click(function() {
var $activeSize = $('.list-inline-item a.active');
// removes active from current
$activeSize.removeClass('active');
var $heading = $('.layout-attachments h1')
//removes the class and add class you want
$heading.removeClass($activeSize.data('newClass'));
$heading.addClass($(this).data('newClass'));
//add active to the clicked one
$(this).addClass("active")
});
JS Fiddle

Maintain the class which alters the font size in the list item as a data attribute and add the new class to the target on click event!
Here is the working solution..
var $item = $('.list-inline-item'),
$target = $('.img-responsive.img-thumbnail');
$item.on('click', function() {
var size = $(this).find('a').data('size');
$target
.removeClass('w-50-p w-75-p w-100-p') // remove size classes
.addClass(size);
});
.w-50-p {
font-size: 1em;
}
.w-75-p {
font-size: 1.5em;
}
.w-100-p {
font-size: 2em;
}
.list-inline-item a {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item"><a data-size="w-50-p">S</a></li>
<li class="list-inline-item"><a data-size="w-75-p">M</a></li>
<li class="list-inline-item"><a data-size="w-100-p">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>

Related

Get child element from element through an event with Vue

Goal
What I'm trying to achieve is that whenever the user clicks on the .menu-item element, the dropdown element .menu-item-dropdown will get a class that will show the element.
Problem
Currently, when I click on the .menu-item class element, the returned value from the console.log in showMobileNavDropdown() returns null. When clicking, the event.target element is .menu-item-main and not .menu-item. This happens only when I click on the text of the li. Otherwise this works as intended.
What would be the best way to include the li text so that I can still grab the .menu-item-dropdown class?
Vue
<template>
<div>
<nav class="nav">
<div class="nav-left">
<img class="logo" src="/images/logo.svg" alt="" />
</div>
<div class="nav-center">
<ul class="menu-items">
<li
class="menu-item"
#click="showMobileNavDropdown($event)"
>
<!-- Main Title On Nav -->
<a class="menu-item-main" href="#">Company</a>
<!-- Dropdown -->
<div class="menu-item-dropdown">
<ul>
<li class="">
About
</li>
<li class="">
Contact
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="nav-right">
Contact us
</div>
<div class="hamburger" #click="openMobileNav">
<span class="ham-line"></span>
<span class="ham-line ham-line-2"></span>
</div>
</nav>
<div class="mobile-nav"></div>
</div>
</template>
<script>
export default {
methods: {
openMobileNav() {
var mobileNav = document.querySelector(".mobile-nav");
mobileNav.classList.toggle("showMobileNav");
},
// This function
showMobileNavDropdown(event) {
console.log(event); // This element returns 'menu-item-main' and not 'menu-item'
console.log(event.target.querySelector(".menu-item-dropdown"));
},
},
};
</script>
Assuming you have a longer list of possible click-targets and can't or won't just use refs, I would use event-delegation and in the click-handler check, whether the clicked element is inside a clickable parent and based on that, toggle a class on the parent, which can then be used to select the child in CSS, for example to change it's opacity.
Vue.component('foo-bar', {
methods: {
toggleSubItemVisibility({ target }) {
const item = target.closest('.nav-item');
// we check because the user might have clicked on the surrounding ul
if (item) {
item.classList.toggle('active');
}
}
},
template: `
<nav>
<ul #click="toggleSubItemVisibility">
<li class="nav-item">
<span class="nav-label">Foo</span>
<div class="nav-sub-item">More details...</div>
</li>
<li class="nav-item">
<span class="nav-label">Bar</span>
<div class="nav-sub-item">More details...</div>
</li>
</ul>
</nav>`
})
new Vue({
el: '#app'
});
nav ul {
list-style-type: none;
display: flex;
flex-direction: row;
gap: 12px;
}
.nav-label {
cursor: pointer;
}
.nav-sub-item {
opacity: 0;
transition: opacity 1s ease;
}
.nav-item.active .nav-sub-item {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<foo-bar></foo-bar>
</div>
The solution was to either grab the element, and if that returned null, grab the sibling. This way, it's always possible to select the .menu-item-dropdown element. When clicking on the element, it can either be a child or sibling.
Part of Solution
var element =
event.target.querySelector(".menu-item-dropdown") ||
event.target.nextElementSibling;
element.classList.toggle("hide_drop");

multiple elements attached to one click event listener

what i want to happen is that on clicking one of the #playlist instances in the unordered list, it will take the corresponding instances inner text and use it to find the rest of the information, like the csv and cover. this is what i have so far but im not sure if im going in the right direction or how to continue. thanks
const playlistCover = document.querySelector('#playlist-cover');
const playlistName = document.querySelector('#playlist-name');
const playlistDuration = document.querySelector('#playlist-duration');
const playlistLength = document.querySelector('#playlist-length');
const playlistSize = document.querySelector('#playlist-size');
const playlistSelector = document.querySelectorAll('.playlist #playlist').forEach(item => {
item.addEventListener('click', event => {
loadPlaylist();
})
})
function loadPlaylist() {
playlistName.innerText = playlist
playlistCover.src = `static/playlists/${playlist}/cover.png`
playlistCSV = `static/playlists/${playlist}/${playlist}.csv`
}
<div class="playlists">
<h3>Playlists</h3>
<ul>
<li class="playlist">
<a id="playlist" href="#hyperpop">hyperpop</a><a id="options">...</a>
</li>
<li class="playlist">
<a id="playlist" href="#uk-rap">uk-rap</a><a id="options">...</a>
</li>
<li class="playlist">
<a id="playlist" href="#misc">misc</a><a id="options">...</a>
</li>
</ul>
</div>
<div class="main">
<div class="playlist-container">
<div class="info">
<div class="playlist-cover">
<img src="static/playlists/uk-rap/cover.png" alt="playlist-cover" id="playlist-cover">
</div>
<div class="playlist-details">
<div class="header">
<h1 id="playlist-name">uk-rap</h1>
</div>
<div id="playlist-data">
<p class="playlist-duration">6 hours 42 minutes</p>
<p class="playlist-songs">192 songs</p>
<p class="playlist-size">372.5 mb </p>
</div>
</div>
</div>
</div>
<script src="static/scripts/playlist loader.js"></script>
</div>
Here is a simplified version of your code.
The way it works is by making the information hidden by default.
Then, when you click on the name of the playlist, the information appears.
This is handled by toggling the hidden class by using elm.classList.toggle().
document.querySelectorAll(".playlist .info")
.forEach(p => p.parentElement.addEventListener(
"click",
() => p.classList.toggle("hidden"))
);
.hidden {
display: none;
}
li {
list-style: none;
}
.playlist>span:hover {
cursor: pointer;
font-weight: bold;
}
<div class="container">
<ul class="playlists">
<li class="playlist">
<span>UK-Rap</span>
<div class="info hidden">
<div class="duration">6 hours 42 mins</div>
<div class="songs">192 songs</div>
<div class="size">372.5 mb</div>
</div>
</li>
<li class="playlist">
<span>Jazz</span>
</li>
<li class="playlist">
<span>Pop</span>
</li>
</ul>
</div>

Making each li of a Ul clickable

I have a simple ul list, as can be seen below:
<div class="container">
<div class="row">
<div class="col">
<h1>My Favorite Meals <span>(1)</span></h1>
<hr>
<ul>
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
</div>
</div>
</div>
What I want to do, is to make this list clickable. So that when you click on one of the Lis, the background color changes, and the selected li will also be assigned a new class.
My JS code isn't working:
var ul = document.getElementById("foo")
var items = ul.getElementsByTagName("li")
for (var i = 0; i < items.length; ++i) {
// do something with items[i], which is a <li> element
var current = items[i]
current.addEventListener("click", onClick)
var onClick = function() {
current.style.backgroundColor = "red"
}
}
HTML:
<div class="container">
<div class="row">
<div class="col">
<h1>My Favorite Meals <span>(1)</span></h1>
<hr>
<ul>
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
</div>
</div>
</div>
CSS:
.backgroundColor {
background-color: lightgray;
}
JS:
var items = document.getElementsByTagName("li")
items.forEach(li => {
li.addEventListener('click', () => {
li.classList.toggle('backgroundColor');
});
});
Hopefully this will help you to solve your problem.
Try something like this:
<div class="container">
<div class="row">
<div class="col">
<h1>My Favorite Meals <span>(1)</span></h1>
<hr>
<ul id="list">
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
</div>
</div>
</div>
<script>
document.getElementById("list").addEventListener("click",function(e) {
if (e.target && e.target.matches("li")) {
e.target.classList.toggle("foo"); // toggle foo class name here
e.target.style.backgroundColor = "red"; // new background color here
}
});
</script>
I assigned your ul element an id of "list" and added a "click" event listener to it. Whenever you click an li element within that list, it will assign the foo class to that clicked element (click again to unassign). Similarly, assign a red background color to that element.
JavaScript - addEventListener on all created li elements
I hope my code solved your problem.
$(document).ready(()=>{
$(".my-list li").each((i)=>{
var myLi = $($(".my-list li")[i]);
myLi.bind("click",()=>{
if(!myLi.hasClass("selected"))
myLi.addClass("selected")
else
myLi.removeClass("selected")
})
})
})
.selected{
background-color:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="my-list">
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
See below. Documentation is inside the code.
// Put a nodelist of li's in variable lis
const lis = document.querySelectorAll("ul li");
// Add an event listener to each li
lis.forEach(li => {
li.addEventListener("click", () => {
// Remove class selected from currently selected li
document.querySelector("ul li.selected").classList.remove("selected");
// Assign class selected to the clicked li
li.classList.add("selected");
});
});
li {
cursor: pointer; /* Change cursor */
}
li.selected {
/* Change background color of selected li */
background-color: lightgreen;
}
<div class="container">
<div class="row">
<div class="col">
<h1>My Favorite Meals <span>(1)</span></h1>
<hr>
<ul>
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
</div>
</div>
</div>

Toggle list items after button click using jQuery

So i managed to get my buttons to show the list items in the unordered list. But now every time i click a button all the list items nested in unordered list appears and disappears when the button is clicked again.
This is my updated HTML:
<div class="container-fluid text-center bg-black" id="services">
<div class="services">
<h2>SERVICES</h2>
<br>
<div class="row">
<div class="col-sm-3 iconpad-even">
<img src="img/icons/icon_data_edit.png" alt="data"/>
<button class="icon-btn" data-button="btnData">DATA</button>
<ul class="showData">
<li>Design</li>
<li>Cable Installation</li>
<li>Testing</li>
<li>CAT5e, CAT6, CAT6A</li>
</ul>
</div>
<div class="col-sm-3 iconpad-odd">
<img src="img/icons/fiber-icon-edit.png" alt="fiber-icon" />
<button class="icon-btn" data-button="btnFiber">FIBER</button>
<ul class="showData">
<li>Consultancy</li>
<li>Building to Building</li>
<li>Network Backbone</li>
<li>Testing</li>
</ul>
</div>
Basically i have 6 div's that are structured the exact same way, only difference is the content on the list items.
I've removed the display:none on the services ul li and added it to the css .showData class as suggested by #Mohammed-Yusef
Here's the current jQuery:
$(function() {
$('.icon-btn').on('click', function() {
$('.showData').toggle();
});
});
The jquery syntax of the click function should be as given below and also in your css you are hiding all the li elements. So you have to toggle them back with the selector $('.showData li') instead of $('.showData'). Also use .icon-btn instead of .icon-button as you don't have such a class mentioned in your html.
$('.icon-btn').on('click', function() {
$('.showData li').toggle();
});
Working snippet,
$(function() {
$('.icon-btn').on('click', function() {
//$('.showData li').toggle();
$(this).next('.showData').find('li').toggle();
});
});
.services ul li {
display: none;
margin-left: -1.8em;
/*color: #fff;*/
list-style: none;
margin-bottom: 1em;
font-size: 20px;
font-weight: bold;
font-family: 'Oswald', 'open-sans';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container-fluid text-center bg-black" id="services">
<div class="services">
<h2>SERVICES</h2>
<br>
<div class="row">
<div class="col-sm-3 iconpad-even">
<img src="img/icons/icon_data_edit.png" alt="data"/>
<button class="icon-btn" data-button="btnData">DATA</button>
<ul class="showData">
<li>Design</li>
<li>Cable Installation</li>
<li>Testing</li>
<li>CAT5e, CAT6, CAT6A</li>
</ul>
</div>
<div class="col-sm-3 iconpad-odd">
<img src="img/icons/fiber-icon-edit.png" alt="fiber-icon" />
<button class="icon-btn" data-button="btnFiber">FIBER</button>
<ul class="showData">
<li>Consultancy</li>
<li>Building to Building</li>
<li>Network Backbone</li>
<li>Testing</li>
</ul>
</div>
Please try it
$( "body" ).on( "click", ".icon-button", function(){
$('.showData').toggle();
});
The problem is that you don't have an element with a class icon-button your button has a class icon-btn so use $('.icon-btn') instead of $('.icon-button')
and you can use
$(function() {
$('.icon-btn').on('click', function() {
$('.showData').toggle();
});
});
and in css use
.showData{
display: none;
}
and remove display:none from .services ul li
Note: be sure to include jquery

jQuery switch active class depending on which section is showing

I have several sections within a document as follows:
<section id="step1">
</section>
<section id="step2" style="display:none">
</section>
<section id="step3" style="display:none">
</section>
I am showing and hiding these depending on user interaction. I wanted to have some kind of circular heading to indicate the user is on section 2 of 3 for example like so:
<div id="indicators" class="clearfix">
<div class="center-div">
<ul>
<li id="step1-circle" class="circle active"></li>
<li id="step2-circle" class="circle"></li>
<li id="step3-circle" class="circle"></li>
</ul>
</div>
</div>
How would I switch the active class depending on which section is showing?
You can use the addClass() method in tandem with the removeClass() method like:
function makeIndicatorCircleActive(id){
// Remove active state of current circle
$('#indicators .active').removeClass('active');
// Add active state to desired element
$(id).addClass('active');
}
// Somewhere else in the code...
makeIndicatorCircleActive('#step2-circle);
I've added a button for the animation. You'd need to show more example code of your implementation, but you may be able to get away with let $section = $('section:visible') and instead of putting this in a click function, create a generic function name, which is triggered whenever your event occurs.
$('button').click(function() {
// context used for jQuery
let $section = $(this).closest('section');
// get next circle, if current circle is last, then get first circle
var $next = $('.circle.active', $section).next('.circle'),
$next = ($next.length && $next) || $('.circle', $section).first();
$('.circle.active', $section).removeClass('active'); // remove all actives
$next.addClass('active'); // add new active
});
.circle {
background: black;
border-radius: 25px;
display: inline-block;
list-style-type: none;
width: 50px;
height: 50px;
-moz-border-radius: 25px;
-webkit-border-radius: 25px;
}
.active {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
<div class="clearfix">
<div class="center-div">
<ul>
<li class="circle active"></li>
<li class="circle"></li>
<li class="circle"></li>
</ul>
</div>
<button>Next</button>
</div>
</section>
<section>
<div class="clearfix">
<div class="center-div">
<ul>
<li class="circle active"></li>
<li class="circle"></li>
<li class="circle"></li>
</ul>
</div>
<button>Next</button>
</div>
</section>

Categories