I'm trying to create a custom drop down menu, using HTML, CSS and Vanilla Javascript.
I've managed to get the menu to appear when the user clicks on the the "from" input field, however when I try and click on an option, it wont let you add the value stored in the "code" dataset.
I did get it to work by using setTimeout method, however it is a bit hit and miss sometimes and doesn't seem like a good solution.
Is there an alternative way to get it to work?
function app() {
var messages = document.querySelector(".messages");
var inputFrom = document.querySelector(".input-from");
var inputTo = document.querySelector(".input-to");
var nearestContainer = document.querySelector(".nearest-container");
inputFrom.addEventListener("focus", inputToFocusIn, false);
function inputToFocusIn(e) {
messages.innerHTML = "focusin event triggered on input-from";
// add class
inputFrom.classList.add("input-from--focusin");
nearestContainer.classList.add("nearest-container--active");
// remove class
inputFrom.classList.remove("input-from--focusout");
nearestContainer.classList.remove("nearest-container--hidden");
}
inputFrom.addEventListener("focusout", inputToFocusOut, false);
function inputToFocusOut(e) {
messages.innerHTML = "focusout event triggered on input-from";
// add class
inputFrom.classList.remove("input-from--focusin");
nearestContainer.classList.remove("nearest-container--active");
// remove class
inputFrom.classList.add("input-from--focusout");
nearestContainer.classList.add("nearest-container--hidden");
}
var nearestStations = document.querySelectorAll(".nearest-station");
// add event listener to buttons
for(var nearestStation of nearestStations) {
nearestStation.addEventListener("click", addToInputFrom, false);
}
function addToInputFrom(e) {
inputFrom.classList.add("input-from--focusout");
nearestContainer.classList.add("nearest-container--hidden");
inputFrom.classList.remove("input-from--focusin")
nearestContainer.classList.remove("nearest-container--active")
var targetDataset = e.currentTarget.dataset.code;
messages.innerHTML = "station added to input from field"
inputFrom.value = "";
inputFrom.value = targetDataset;
}
var switchButton = document.querySelector(".button-switch");
switchButton.addEventListener("click", clickSwitch, false);
function clickSwitch(e) {
var inputFromValue = inputFrom.value;
var inputToValue = inputTo.value;
inputFrom.value = inputToValue;
inputTo.value = inputFromValue;
}
}
window.onload = app();
/* stylesheet */
body {
font-family: "GRAPHIK";
font-style: normal;
font-weight: 400;
font-size: 16px;
color: #242424;
}
* {
box-sizing: border-box;
outline: none;
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background-color: #FF4136;
}
.search-container {
display: flex;
flex-direction: column;
flex-shrink: 0;
width: 300px;
padding: 10px;
background-color: #FFF;
border-radius: 10px;
}
.form-container {
display: flex;
flex-direction: row;
width: 100%;
}
.input-container {
width: 100%;
}
.input {
width: 100%;
border: none;
border-radius: 10px;
background-color: #f1f1f1;
padding: 10px;
}
.input-from {
margin-bottom: 5px;
}
.input-from--focusout {
border-radius: 10px;
}
.input-from--focusin {
border-radius: 10px 10px 0 0;
}
.input-to {
margin-bottom: 5px;
}
.switch-container {
margin-bottom: 5px;
}
.button {
border: none;
background-color: transparent;
}
.button-switch {
height: 100%;
width: 38px;
margin-left: 5px;
background-color: #f1f1f1;
border-radius: 10px;
background-image: url(../assets/images/switch.svg);
background-position: center;
background-size: 20px;
background-repeat: no-repeat;
}
.button-switch:hover {
background-image: url(../assets/images/switch-hover.svg);
}
.button-search {
padding: 10px;
background-color: #2ECC40;
color: #FFF;
border-radius: 10px;
width: 100%;
transition: background-color 0.5s ease;
}
.button-search:hover {
background-color: #33e147;
}
.input-container-to {
position: relative;
}
.nearest-container {
position: absolute;
top: 38px;
background-color: #f1f1f1;
padding: 5px;
border-radius: 0 0 10px 10px;
width: 100%;
z-index: 100;
}
.messages {
width: 300px;
background-color: #FFF;
padding: 5px;
border-radius: 10px;
text-align: center;
margin-bottom: 5px;
font-size: 10px;
}
.finding, .show-more {
width: 100%;
font-size: 10px;
font-style: italic;
margin: 0;
padding: 5px;
}
.show-more {
text-align: center;
}
.nearest-station {
font-size: 10px;
padding: 5px;
border-radius: 10px;
}
.nearest-container--hidden {
display: none;
}
.nearest-station--active {
display: flex;
}
.nearest-station:hover {
background-color: #FFF;
cursor: pointer;
}
.logo {
margin-right: 5px;
}
.nr-logo {
width: 15px;
}
.station-distance {
font-style: italic;
float: right;
}
<div class="container">
<div class="messages">messages here</div>
<div class="search-container">
<div class="form-container">
<div class="input-container">
<div class="input-container-to">
<input type="text" class="input input-from" placeholder="From">
<div class="nearest-container nearest-container--hidden">
<div class="stations-container">
<p class="finding">Finding stations closest to you...</p>
<!-- stations here-->
<div class="nearest-station" data-code="Leigh-on-Sea">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Leigh-on-Sea</span>
<span class="station-distance">0.6km</span>
</div>
<div class="nearest-station" data-code="Chalkwell">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Chalkwell</span>
<span class="station-distance">1.5km</span>
</div>
<div class="nearest-station" data-code="Westcliff">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Westcliff</span>
<span class="station-distance">2.7km</span>
</div>
<div class="nearest-station" data-code="Southend Central">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Southend Central</span>
<span class="station-distance">3.6km</span>
</div>
<div class="nearest-station" data-code="Southend Victoria">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Southend Victoria</span>
<span class="station-distance">3.8km</span>
</div>
</div>
<div class="stations-show-more">
<!--
<p class="show-more">Show more stations</p> -->
</div>
</div>
</div>
<div class="input-container-to">
<input type="text" class="input input-to" placeholder="To">
</div>
</div>
<div class="switch-container">
<input type="button" class="button button-switch">
</div>
</div>
<div class="button-search-container">
<input type="button" class="button button-search" value="Search">
</div>
</div>
</div>
Using setTimeout in the inputToFocusOut() function is indeed the correct way to obtain the desired effect: hiding of the menu must be delayed so that a click on a menu item will register and its callback will fire. There should be nothing hit and miss about it, just set the delay at a reasonable value, say 300ms, and remove the hiding of the menu from the addToInputFrom() callback. Actually, you can remove all of the latter function's class-toggling calls, as they are redundant there and may interfere. The menu will be shown/hidden by virtue of inputFrom gaining/losing focus.
BTW, why are you using focusout and not blur?
Using focusout event here
inputFrom.addEventListener("focusout", inputToFocusOut, false);
is not right. Because it will be triggered before click event.
When the function inputToFocusOut is executed the .nearest-container becomes hidden:
nearestContainer.classList.add("nearest-container--hidden");
and that's why click event for it and all of its child nodes (we are interested in .nearest-station elements) won't be triggered. Instead of focusout, use mousedown event. With blur event it won't work.
Related
there is a filter on the js, which consists of three identical buttons (named "green", "yellow", "red"), which are responsible for setting/removing the blur effect for the set of pictures located below.
When pressing the "green" button, a blur effect should be set for all pictures that have a value "green" of data-card property.
At the second click on the same button, the blur effect should be canceled for this category of pictures.
I solved this problem with a reception with a boolean flag:
let firstClick = true;
if (firstClick){
//..do at first click
firstClick = !firstClick;
}
else{
//..do at second click
firstClick = !firstClick;
}
However, the problem occurs when I click on the "green" button (this is the first click on the "green" button), and after that on another button, for example "red" (this is the first click on the "red" button). But the compiler perceives a click on the "red" button as a second click, although it is a different button.
The question is how to distinguish the behavior in different buttons?
In general, I solved the problem through a complete search and many if statements. Maybe there is an alternative way?
Project demo in codepen
//main.js
function app() {
const buttons = document.querySelectorAll('.service__btn');
const cards = document.querySelectorAll('.service__item');
let firstClick = true;
function setBlour(listOfCards) {
listOfCards.forEach(item => {
if (item.classList.contains(currentCategory)) {
item.classList.add('blur');
}
});
}
function resetBlour(listOfCards) {
listOfCards.forEach(item => {
if (item.classList.contains(currentCategory)) {
item.classList.remove('blur');
}
});
}
function highlightButton(butt) {
if (!butt.classList.contains('service__btn__clicked')) {
butt.classList.add('service__btn__clicked');
}
firstClick = !firstClick;
}
function unhighlight(butt) {
if (butt.classList.contains('service__btn__clicked')) {
butt.classList.remove('service__btn__clicked');
}
firstClick = !firstClick;
}
buttons.forEach(button => {
button.addEventListener('click', (event) => {
currentCategory = event.target.dataset.filter; //current category we get from clicked button
let matchedCards = document.querySelectorAll(`[data-card="${button.dataset.filter}"]`);
//is it first click?
if (firstClick) {
if (!matchedCards[0].classList.contains('blur')) { // each click we have set of matchedCards, it's easy to check one of them (the first for example) if it have blur
setBlour(matchedCards);
highlightButton(button);
} else { //it is a first clcik, but card have blur - so remove blur
resetBlour(matchedCards);
unhighlight(button);
}
}
//second click
else {
if (!matchedCards[0].classList.contains('blur')) { //if there is no blur - add blur
setBlour(matchedCards);
highlightButton(button);
} else { //second click and blur is present - so we need to remove it
resetBlour(matchedCards);
unhighlight(button);
}
}
});
});
}
app()
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
margin: 0;
padding: 0;
}
a {
text-decoration: none;
}
li {
list-style-type: none;
}
.container {
width: 1220px;
margin: 0 auto;
}
.service {
background: #EDF2EC;
padding-top: 40px;
padding-bottom: 70px;
}
.service__top {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.service__top-title {
font-family: 'Inika', serif;
font-weight: 400;
font-size: 40px;
line-height: 52px;
color: #499A18;
max-width: 306px;
}
.service__filter-btn {
margin-left: 142px;
}
.service__btn {
border: 1px solid #E06733;
border-radius: 5px;
padding: 12px 40px;
font-family: 'Inika', serif;
font-weight: 400;
font-size: 20px;
line-height: 26px;
color: #E06733;
}
.service__btn__clicked {
background: #E06733;
border: 1px solid #E06733;
border-radius: 5px;
color: #FFFFFF;
}
.service__btn+.service__btn {
margin-left: 32px;
}
.service__content {
column-count: 3;
gap: 0 116px;
}
.service__item {
margin-bottom: 55px;
text-align: center;
width: 330px;
height: 350px;
border-radius: 20px;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.service__item-title {
font-family: 'Inter', sans-serif;
font-weight: 700;
font-size: 20px;
line-height: 20px;
color: #E06733;
margin-top: 10px;
margin-bottom: 10px;
}
.service__item-text {
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 16px;
line-height: 20px;
color: #717171;
margin-bottom: 36px;
}
.service__item-description {
border-radius: 0px 0px 20px 20px;
border: 1px solid #e3e1d5;
display: none;
}
.blur {
filter: blur(5px);
}
.animation {
transform: scale(0);
opacity: 0;
}
<body>
<section class="service">
<div class="container">
<div class="service__top">
<h3 class="service__top-title">
Caption and Description
</h3>
<div class="service__filter-btn">
<button class="service__btn service__btn-type_green" data-filter="green"> Green</button>
<button class="service__btn service__btn-type_yellow" data-filter="yellow">Yellow</button>
<button class="service__btn service__btn-type_red" data-filter="red">Red</button>
</div>
</div>
<div class="service__content">
<div class="service__item green" data-card="green">
<div class="service__item-description">
<h4 class="service__item-title">Green color</h4>
<p class="service__item-text">Description</p>
</div>
</div>
<div class="service__item red" data-card="red">
<div class="service__item-description">
<h4 class="service__item-title">Red color</h4>
<p class="service__item-text">Description</p>
</div>
</div>
<div class="service__item yellow" data-card="yellow">
<div class="service__item-description">
<h4 class="service__item-title">Yellow color</h4>
<p class="service__item-text">Description</p>
</div>
</div>
<div class="service__item red" data-card="red">
<div class="service__item-description">
<h4 class="service__item-title">Red color</h4>
<p class="service__item-text">Description</p>
</div>
</div>
<div class="service__item green" data-card="green">
<div class="service__item-description">
<h4 class="service__item-title">Green color</h4>
<p class="service__item-text">Description</p>
</div>
</div>
<div class="service__item red" data-card="red">
<div class="service__item-description">
<h4 class="service__item-title">Red color</h4>
<p class="service__item-text">Description</p>
</div>
</div>
</div>
</div>
</section>
</body>
I'm trying to make a toggle switch work, which will show/hide classes based on if it is checked or unchecked. By default i want to show "pay annually" so it will display the annual price, also a text blub further down the page. If i click "pay monthly" it will display the monthly price, and a monthly text blurb further down the page.
I tried to follow some solution, but at the moment all are showing, and nothing toggles. How can i fix this?
link to codepen
function showHide(e) {
const el = e.target;
if (el.checked) {
el.dataset.checked.split(',').forEach(fld => document.getElementById(fld).parentNode.style.display = 'block');
el.dataset.notChecked.split(',').forEach(fld => document.getElementById(fld).parentNode.style.display = 'none' );
} else {
el.dataset.checked.split(',').forEach(fld => document.getElementById(fld).parentNode.style.display = 'none' );
el.dataset.notChecked.split(',').forEach(fld => document.getElementById(fld).parentNode.style.display = 'block');
}
}
Using jQuery :
$(document).ready(function() {
var checkBoxes = $("input[name='toggle']");
toggle();
$("#toggle").click(function() {
toggle();
});
function toggle() {
if (checkBoxes.prop("checked")) {
$('#coreMonthlyText,#coreMonthlyPrice').show('slow');
$('#coreAnnuallyText,#coreAnnuallyPrice').hide('slow');
} else {
$('#coreMonthlyText,#coreMonthlyPrice').hide('slow');
$('#coreAnnuallyText,#coreAnnuallyPrice').show('slow');
}
}
});
.pricing-box {
background: red;
padding: 25px
}
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.column {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
}
.toggle-switch {
cursor: pointer;
background-color: gray;
display: inline-block;
border: 0;
padding-left: 0;
padding-right: 0;
}
.toggle-switch input {
display: none;
}
.toggle-switch,
.toggle-switch span {
border-radius: 35px;
border-style: solid;
border-color: transparent;
padding-top: .75rem;
padding-bottom: .75rem;
}
.toggle-switch span {
border-width: 2px;
padding-left: .75rem;
padding-right: .75rem;
}
.toggle-switch input:checked+span+span,
.toggle-switch input+span {
border-color: #444;
background-color: white;
}
.toggle-switch input+span+span,
.toggle-switch input:checked+span {
background-color: transparent;
border-color: transparent;
}
#coreMonthlyText,
#coreMonthlyPrice,
#coreAnnuallyText,
#coreAnnuallyPrice {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="pricing-box">
<div class="row">
<div class="column">
<div class="core">
<h2>Core</h2>
</div>
</div>
<div class="column">
<div id="coreAnnuallyPrice" class="coreAnnuallyPrice">
$2,399/yr<br /> Normally $3,588/yr
</div>
<div id="coreMonthlyPrice" class="coreMonthlyPrice">
$299/pm<br /> first 2 months free
</div>
</div>
</div>
<label for="toggle" class="toggle-switch">
<input class="toggle-button" id="toggle" type="checkbox" name="toggle" data-checked="coreAnnuallyPrice,coreAnnuallyText" data-not-checked="coreMonthlyPrice,coreMonthlyText">
<span>pay annually</span>
<span>pay monthly</span>
</label>
</div>
<p id="coreAnnuallyText" class="center_text big-text coreAnnuallyText">this is a annual text blurb</p>
<p id="coreMonthlyText" class="center_text big-text coreMonthlyText">this is a monthly text blurb.</p>
I have 2 blocks for user to choose from and they should be interactive. The block changes the color and the vertical line color should be changed to opposite. I wonder if I could make it right in the same code snippet which does the color change of the code block, because previously I made it, but with another for loop and it's not the fastest way.
let vanOption = document.getElementsByClassName("van-quote-option");
let quoteVl = document.getElementById("option-vl");
// Van option selection
for (var x = 0; x < vanOption.length; x++) {
vanOption[x].addEventListener("click", function() {
var currentOption = document.getElementsByClassName("option-active");
if (currentOption.length > 0) {
currentOption[0].className = currentOption[0].className.replace(" option-active", "");
}
this.className += " option-active";
});
}
.van-quote-option {
display: flex;
justify-content: space-evenly;
margin: 25px 165px 20px 165px;
border: 1px solid grey;
cursor: pointer;
transition: 0.5s;
}
.option-active {
background-color: #18A063;
color: #fff;
}
.quote-vl {
border-left: 2px solid #13985C;
height: 116px;
}
.quote-vl-active {
border-left: 2px solid #fff;
height: 116px;
}
.quote-icon {
margin: 25px 0 0 35px;
}
.quote-van-icon {
font-size: 49px;
padding: 8px;
border-radius: 50%;
height: 60px;
background-color: rgb(245, 245, 245);
color: #18A063;
}
.quote-car-icon {
font-size: 49px;
padding: 9px;
height: 52px;
background-color: rgb(245, 245, 245);
color: #18A063;
border-radius: 50%;
}
.quote-bicycle-icon {
font-size: 49px;
padding: 10px;
height: 55px;
background-color: rgb(245, 245, 245);
color: #18A063;
border-radius: 50%;
}
.quote-p {
text-align: left;
}
.quote-p-van {
text-align: left;
margin-top: 5px;
}
.bicycle-quote-vl,
.car-quote-vl {
height: 124px;
}
.quote-price {
display: flex;
flex-direction: column;
justify-content: center;
}
.quote-price-van {
margin-top: 10px;
}
.van-send-price,
.car-send-price,
.bicycle-send-price {
font-size: 25px;
font-weight: 700;
}
.van-send-price::before,
.car-send-price::before,
.bicycle-send-price::before {
content: "\00A3";
}
<div class="quote-options">
<div class="van-quote-option option-active">
<div class="quote-icon quote-icon-1">
<i class="fas fa-truck quote-van-icon"></i>
</div>
<div class="quote-p-van">
<div class="quote-p-1">Sending 1 or 2 items (with van)</div>
<br />
<div class="quote-p-2">
We'll take a maximum of 2 items for you<br />
to deliver immediately at any location.
</div>
</div>
<div class="quote-vl quote-vl-active"></div>
<div class="quote-price-van">
<span class="van-send-price" id="van-deliver-price">14</span><br />
For a max.<br />
of 2 items.
</div>
</div>
<div class="van-quote-option">
<div class="quote-icon quote-icon-1">
<i class="fas fa-truck quote-van-icon"></i>
</div>
<div class="quote-p-van">
<div class="quote-p-1">Hire a van</div>
<br />
<div class="quote-p-2">
We'll take a maximum of 2 items for you<br />
to deliver immediately at any location.
</div>
</div>
<div class="quote-vl"></div>
<div class="quote-price-van">
<span class="van-send-price" id="van-deliver-price">38</span><br />
Hire a van,<br />
∞ items
</div>
</div>
</div>
You can fix this with css.
You don't really need the quote-vl-active class. Remove it.
You can refer to the vertical line when it's active using option-active since it's the child of that element.
.option-active > .quote-vl {
border-left: 2px solid white;
height: 116px;
}
See this fiddle: https://jsfiddle.net/29r1v0Lo/
might want to use onclick vs. adding listeners as well.
Here is a jsfiddle of it a bit cleaner and with the vert bar having the opposite color: https://jsfiddle.net/7L0uzkxj/
You can just have the CSS control the vert bar:
.quote-vl {
border-left: 2px solid green;
height: 116px;
}
.option-active .quote-vl {
border-left: 2px solid white;
height: 116px;
}
You can then clean up the JS to look like this:
function triggerMe(evt) {
let vanOption = document.getElementsByClassName("van-quote-option");
[...vanOption].forEach(x => {
if (x.classList.contains('option-active')) {
x.classList.remove('option-active');
}
})
evt.classList.toggle('option-active');
}
I have a button of fixed size and various chunks of text. The length of the texts is different. How can I make the size of the text font change dynamically according to its length in order to fit the button boundaries properly? Thank you.
Well, depends. Is the height fix as well? If both height and width are fixed, you will have to calculate the fontsize via javascript.
In most of the cases two or three if conditions should be absolutely sufficient for the specific usecase.
function font_size_adjust () {
// Grab the string
var string = $('#button_text').text()
// Get the length in characters of the string
var string_size = string.length
// Build variable to change attribute
var font_size = 0
// Define logic for resizing, adapt this to your personal needs
if (string_size < 60) {
fontsize = '2vw';
} else if (string_size > 60) {
fontsize = '4vw';
} else {}
// Change fontsize
$('#button_text').css('font-size', fontsize)
}
// Call the function where- and whenever needed:
font_size_adjust();
// Example stuff
$('#toggle_small').click(function () {
$('#button_text').text('Now I am small again!')
font_size_adjust();
})
$('#toggle_big').click(function () {
$('#button_text').text('Now I am large again! Lets get this rollin! rollin! rollin! rollin!')
font_size_adjust();
})
#ctn {
display: flex;
float: left;
}
#button {
width: 45vw;
background-color: lightblue;
padding: 10px;
border-radius: 25px;
margin-right: 1vw;
font-family: Varela Round;
color: #FFF;
background: linear-gradient(126deg, rgba(143,61,217,1) 12%, rgba(109,35,177,1) 43%, rgba(101,34,162,1) 72%);
}
#ctn_toggle {
display: flex;
float: left;
}
.toggle {
background-color: lightblue;
font-size: 3vw;
padding: 10px;
border-radius: 25px;
width: 11vw;
text-align: center;
margin-right: 2vw;
font-family: Varela Round;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Varela+Round&display=swap" rel="stylesheet">
<html>
<body>
<div id="ctn">
<div id="button">
<p id="button_text">Make me small and big all day long this is so exciting! Let's go broooh!</p>
</div>
</div>
<div id="ctn_toggle">
<div id="toggle_small" class="toggle">
<p id="button_small">Click me to shrink!</p>
</div>
<div id="toggle_big" class="toggle">
<p id="button_big">Click me to expand!</p>
</div>
</div>
</body>
</html>
Otherwise, these are the options... :
#ctn {
display: flex;
float: left;
}
#button {
width: 20vw;
background-color: lightblue;
padding: 10px;
border-radius: 25px;
margin-right: 1vw;
}
#button_text {
font-size: 4vw;
}
#button2 {
width: 20vw;
background-color: lightblue;
padding: 10px;
border-radius: 25px;
margin-right: 1vw;
}
#button_text2 {
}
#button3 {
width: 20vw;
height: 10vh;
background-color: lightblue;
padding: 10px;
border-radius: 25px;
margin-right: 1vw;
}
#button_text3 {
font-size: 4vw;
}
#button4 {
width: 20vw;
height: 10vh;
background-color: lightblue;
padding: 10px;
border-radius: 25px;
}
#button_text4 {
}
<html>
<body>
<div id="ctn">
<div id="button">
<p id="button_text">Fix button width and fix font-size</p>
</div>
<div id="button2">
<p id="button_text2">Fix button width and no specific font-size</p>
</div>
<div id="button3">
<p id="button_text3">Fix button width, fix button height and fix font-size</p>
</div>
<div id="button4">
<p id="button_text4">Fix button width, fix button height and no font-size</p>
</div>
</div>
</body>
</html>
I wrote some code with three things in mind:
Highlighting a selection's border using 'on click'.
Selecting one item will remove the highlight from the other item.
The ability to deselect each item on click.
I've managed to get everything working for the most part, but I don't particularly like how complex the code is for the radial dot that appears when one item is selected.
Below is an example of what I'm talking about, particularly I'm looking for ways to refactor the code below into something a little more legible (shorter).
$(this).children('.radial').children().toggleClass('checked').parents('.itembox')
.siblings().children('.radial').children().removeClass('checked');
Here's a working example for more context (line 10):
var raceInternet = false;
var racePhone = false;
var raceTv = false;
$(function() {
var $targetDiv = $('#race-internet > .itembox');
var $radialDot = $('.radial > .center-dot');
$targetDiv.on('click', function() {
$(this).toggleClass('user-selected').siblings().removeClass('user-selected');
//Is it possible to refactor Line 10?
$(this).children('.radial').children().toggleClass('checked').parents('.itembox').siblings().children('.radial').children().removeClass('checked');
if ($targetDiv.is('.user-selected')) {
raceInternet = true;
} else {
raceInternet = false;
}
})
})
.itembox-container {
display: flex;
}
.boxes-2 {
width: calc((100% - 25px)/2);
margin: 10px;
padding: 10px;
}
.itembox {
position: relative;
display: inline-block;
border: 5px solid #e8e8e8;
border-radius: 10px;
cursor: pointer;
}
.user-selected {
border: 5px solid #E16E5B;
}
.itembox h4 {
color: #22ddc0;
font-weight: 700;
}
span.price {
display: inline-block;
font-weight: 400;
float: right;
color: #22ddc0;
}
.itembox > ul {
list-style: none;
}
.itembox > ul > li {
line-height: 3;
}
.radial {
position: absolute;
float: right;
height: 35px;
width: 35px;
padding: 2px;
border: 5px solid #e8e8e8;
border-radius: 50%;
top: 43%;
right: 10px;
}
.center-dot {
display: none;
position: relative;
height: 21px;
width: 21px;
background-color: #E16E5B;
border-radius: 50%;
}
.checked {
display: block;
}
.prime-aux:first-of-type {
top: 150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">
<!-- Primary Content Container -->
<div class="prime-aux">
<div id="race-internet" class="itembox-container">
<div class="itembox boxes-2">
<h4>Gigabit Internet <span class="price">$60/mo</span></h4>
<ul>
<li>1,000 Mbps</li>
<li>No data caps</li>
</ul>
<div class="radial">
<div class="center-dot"></div>
</div>
</div>
<div class="itembox boxes-2">
<h4>Basic Internet <span class="price">$25/mo</span></h4>
<ul>
<li>25 Mbps</li>
<li>No data caps</li>
</ul>
<div class="radial">
<div class="center-dot"></div>
</div>
</div>
</div>
</div>
</section>
<!-- Primary Content Container End -->
View on JS Fiddle
You can eliminate a lot of your jQuery by just leveraging CSS. Typically, if I want to toggle a feature, I have it either display: block; or display: none; based upon a CSS selector. Then, I just use jQuery to toggle the parent element's class name. So for example:
.item.selected .checkmark {
display: block;
}
.item .checkmark {
display: none;
}
$('.item').click(function(){ $(this).toggleClass('selected') });
JSFiddle