Menu manage hover and click events - javascript

I have a menu that I want to add hover and click events to.
$('a').hover(function(){
$(this).css('background', 'red');
}, function(){
$(this).css('background', '');
});
$('a').click(function(){
$(this).css('background', 'green');
});
Here is the demo:
https://jsfiddle.net/u2dn68bg/18/
How can I stop my hover event from overriding the click event? i.e. if I have already clicked an element the hover event should not get triggered for that clicked element.

Use CSS rules and toggle a class.
$("a").on("click", function (e) {
e.preventDefault();
$(this).toggleClass("active");
})
a.active, a.active:hover {
background-color: green;
}
a:hover {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
One
Two
Three
Four
based on your comment to not use CSS which is a bad design pattern....
$("a").on("click", function (e) {
e.preventDefault();
let color = ''
if (!this.dataset.active) {
this.dataset.active = 1
color = 'green'
} else {
delete this.dataset.active
}
this.style.backgroundColor = color;
}).on("mouseenter mouseleave", function (e) {
if (this.dataset.active) return
const color = e.type === "mouseenter" ? "red" : ""
this.style.backgroundColor = color;
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
One
Two
Three
Four

Toggle a CSS class when the element is clicked. When you hover, only change the background if the element do not have that certain class.
$('a').hover(function(){
!$(this).hasClass('clicked') && $(this).css('background', 'red');
}, function(){
!$(this).hasClass('clicked') && $(this).css('background', '');
});
$('a').click(function(){
$(this).css('background', 'green').toggleClass('clicked');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="list-inline menu list-unstyled">
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>

Related

How to change hover color using onclick button

I want to switch multiple colors in a page like theme change. I successfully changed text color, text background color, shapes color, button color etc. But I also want to change hover color.
This is the html code:-
<ul class="color-changer">
<li>RED</li>
<li>GREEN</li>
<li>BLUE</li>
</ul>
This code works:-
<script>
$('#red').click(function () {
$('.sidebar button').css({
'background-color': 'red'
});
$('.text-color').css({
'background-color': 'red'
});
$('.shape-left').css({
'background-color': 'red'
});
});
</script>
But this dont work:-
<script>
$('#red').click(function () {
$('.sidebar button:hover').css({
'background-color': 'red'
});
});
</script>
Please help me. I dont know how to solve it.
Here is a solution using CSS variables changed through Javascript. I'll recommend you read the documentation to better understand what is happening here.
let themes = {
red: {
'--sidebar-bg': '#FFAEBE',
'--sidebar-a-color': '#88001B',
'--sidebar-a-hover-color': '#FF0033',
},
green: {
'--sidebar-bg': '#BBFFAE',
'--sidebar-a-color': '#148800',
'--sidebar-a-hover-color': '#3DFF00',
},
blue: {
'--sidebar-bg': '#AEEFFF',
'--sidebar-a-color': '#006E88',
'--sidebar-a-hover-color': '#00CEFF',
},
};
$('.color-changer').on('click', 'a', (e) => {
e.preventDefault();
let theme = $(e.target).data('theme');
setSidebarTheme(theme);
});
function setSidebarTheme(theme) {
let sidebar = $('#sidebar')[0]; // Get the raw Element, not jQuery
for(let [prop, value] of Object.entries(themes[theme])) {
// set value to the CSS variable
sidebar.style.setProperty(prop, value);
}
}
// initial theme
setSidebarTheme('blue');
#sidebar { padding: 20px; }
#sidebar {
background: var(--sidebar-bg);
}
#sidebar a {
color: var(--sidebar-a-color);
}
#sidebar a:hover {
color: var(--sidebar-a-hover-color);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="sidebar">
<ul class="color-changer">
<li>RED</li>
<li>GREEN</li>
<li>BLUE</li>
</ul>
</div>
#red:hover
{
background-color:"color"
}
For all id(red,green,blue) you can do this in css
using variable and hover() you could do the job: (you cant modify css style with :hover)
var red = {'background-color': 'red'};
var redhover = {'background-color': 'yellow'};
$('#red').click(function() {
$('.sidebar button').css(red);
$('.text-color').css(red);
$('.shape-left').css(red);
redhover = {'background-color': 'pink'};
});
$(".sidebar button").hover(function() {
$(this).css(redhover);
},function() {
$(this).css("background-color", "");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="color-changer">
<li>RED</li>
<li>GREEN</li>
<li>BLUE</li>
</ul>

jquery focus to sibling without focusing out from parent

I am try to iterate through all li elements in ul on keydown event by firing focus() event for next sibling li. In this process, I dont want to focus out from parent ul.
But its not happening. Even changing focus on siblings is causing focusout event on parent. I want that only when someone clicks somewhere else on the screen should focus out of parent be fired.
var KEY_DOWN=40;
$(document).on('keydown', 'li', function(e){
let keyCode = e.keyCode || e.which;
if(keyCode == KEY_DOWN)
{
if($(this).next().length != 0)
{
$(this).next().focus();
}
else
{
$(this).parent().children().first().focus();
}
return false;
}
});
$(document).on('focusout','ul', function(e)
{
console.log('focused')
});
li
{
border: 1px solid black;
}
li:focus
{
background: #999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul tabindex="-1">
<li tabindex="-1">First</li>
<li tabindex="-1">Second</li>
<li tabindex="-1">Third</li>
</ul>
In the snippet, focused in getting printed on every down key press. How to solve this situation.
Due to event bubbling, the focusout event is logging the message for you when you are focusing out of li too. You can use the event data to check from where you have focused out. (Read more here: jQuery figuring out if parent has lost 'focus')
But I would like to mention how I do it. I would rather like to detect click outside my ul.
var KEY_DOWN=40;
$(document).on('keydown', 'li', function(e){
let keyCode = e.keyCode || e.which;
if(keyCode == KEY_DOWN)
{
if($(this).next().length != 0)
{
$(this).next().focus();
}
else
{
$(this).parent().children().first().focus();
}
return false;
}
});
$(document).on('focusout','ul', function(e)
{
console.log('focused out of li');
});
$(document).click(function() {
console.log('focused out of ul');
});
$('ul').click(function(e) {
e.stopPropagation();
});
li
{
border: 1px solid black;
}
li:focus
{
background: #999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul tabindex="-1">
<li tabindex="-1">First</li>
<li tabindex="-1">Second</li>
<li tabindex="-1">Third</li>
</ul>
Only way I found was to disable focusout event on parent ul when I am trying to focus any li
var KEY_DOWN=40;
$(document).on('keydown', 'li', function(e){
let keyCode = e.keyCode || e.which;
if(keyCode == KEY_DOWN)
{
$(document).off('blur','ul', doWork);
if($(this).next().length != 0)
{
$(this).next().focus();
}
else
{
$(this).parent().children().first().focus();
}
$(document).on('blur','ul', doWork);
return false;
}
});
doWork = function(e)
{
console.log('focused')
};
$(document).on('blur','ul', doWork);
li
{
border: 1px solid black;
}
li:focus
{
background: #999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul tabindex="-1">
<li tabindex="-1">First</li>
<li tabindex="-1">Second</li>
<li tabindex="-1">Third</li>
</ul>

Adding directional controls (prev/next) to switch between tabs

I've just finished a creating a bare bones JavaScript tabs functionality for website. Right now I'm having a bit of problem trying to add directional functions in order to switch between tabs. Here is what I've created so far. I'm not sue on how I can increment or decrement the index in order to use the directional arrows to switch tabs and also the content
$(document).ready(function() {
$('.tabs-list li:first-child').addClass('active'),
$('.tab-content .show-content:first-child').addClass('active');
$('.tabs-list li').click(function(e) {
event.preventDefault();
if (!$(this).hasClass('active')) {
var tabIndex = $(this).index();
var nthChild = tabIndex + 1;
// select the right elements
var $tabsList = $(this).parent();
var $tabContent = $tabsList.next('.tab-content');
$tabsList.find('li.active').removeClass('active');
$(this).addClass('active');
$tabContent.find('.show-content').removeClass('active');
$tabContent.find('.show-content:nth-child(' + nthChild + ')').addClass('active');
}
})
$('.prev').on('click', function() {});
$('next').on('click', function() {});
})
.tabs-list li {
display: inline-block;
}
.tab-content .show-content {
display: none
}
.tab-content .show-content.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul class="tabs-list">
<li>Tab 1</li>
<li>Tab 2</li>
<li>Tab 3</li>
</ul>
<div class="tab-content">
<div class="show-content">
Content 1
</div>
<div class="show-content">
Content 2
</div>
<di>
Content 3
</di>
</div>
</div>
<ul>
<li class="prev">Prev</li>
<li class="next">Next</li>
</ul>
You can do it using jQuery .prev() and .next() methods. You just need to get the current .active tab and change it accordingly.
Here's the code you need:
$('.prev').on('click', function() {
var current = $('.tab-content .show-content.active');
if (current.prev('.tab-content .show-content')[0]) {
current.removeClass('active');
current.prev('.tab-content .show-content').addClass('active');
}
});
$('.next').on('click', function() {
var current = $('.tab-content .show-content.active');
if (current.next('.tab-content .show-content')[0]) {
current.removeClass('active');
current.next('.tab-content .show-content').addClass('active');
}
});
Demo:
This is a working Fiddle and a working Demo snippet:
$(document).ready(function() {
$('.tabs-list li:first-child').addClass('active'),
$('.tab-content .show-content:first-child').addClass('active');
$('.tabs-list li').click(function(e) {
event.preventDefault();
if (!$(this).hasClass('active')) {
var tabIndex = $(this).index();
var nthChild = tabIndex + 1;
// select the right elements
var $tabsList = $(this).parent();
var $tabContent = $tabsList.next('.tab-content');
$tabsList.find('li.active').removeClass('active');
$(this).addClass('active');
$tabContent.find('.show-content').removeClass('active');
$tabContent.find('.show-content:nth-child(' + nthChild + ')').addClass('active');
}
})
$('.prev').on('click', function() {
var current = $('.tab-content .show-content.active');
if (current.prev('.tab-content .show-content')[0]) {
current.removeClass('active');
current.prev('.tab-content .show-content').addClass('active');
}
});
$('.next').on('click', function() {
var current = $('.tab-content .show-content.active');
if (current.next('.tab-content .show-content')[0]) {
current.removeClass('active');
current.next('.tab-content .show-content').addClass('active');
}
});
})
.tabs-list li {
display: inline-block;
cursor: pointer;
}
.tab-content .show-content {
display: none
}
.tab-content .show-content.active {
display: block;
}
.as-console-row-code {
display: none;
}
.prev,
.next {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul class="tabs-list">
<li>Tab 1</li>
<li>Tab 2</li>
<li>Tab 3</li>
</ul>
<div class="tab-content">
<div class="show-content">
Content 1
</div>
<div class="show-content">
Content 2
</div>
<div class="show-content">
Content 3
</div>
</div>
</div>
<ul>
<li class="prev">Prev</li>
<li class="next">Next</li>
</ul>
Edit:
To make it loop in a cyclic way and doesn't stop in first or last elements, we should just implement that in the else block of our if statement, so it won't stop.
Here's how will be your code:
$('.prev').on('click', function() {
var current = $('.tab-content .show-content.active');
if (current.prev('.tab-content .show-content')[0]) {
current.removeClass('active');
current.prev('.tab-content .show-content').addClass('active');
} else {
current.removeClass('active');
$(".tab-content .show-content:last").addClass('active');
}
});
$('.next').on('click', function() {
var current = $('.tab-content .show-content.active');
if (current.next('.tab-content .show-content')[0]) {
current.removeClass('active');
current.next('.tab-content .show-content').addClass('active');
} else {
current.removeClass('active');
$(".tab-content .show-content:first").addClass('active');
}
});
And this is an updated Fiddle taking in consideration these changes.

How to open a box on screen by clicking a link and hide it when clicked outside in JS

My goal is to have #box2 appear when I click on #box1 but when you click on something other than #box2, it will display none and only #box1 will show.
Here are my 2 boxes, they are just 2 styled divs:
var condition;
$(document).click(function() {
if (condition === 'block') {
$(":not(#box2)").click(function() {
$("#box2").hide();
});
}
})
$('#box1').click(function(e) {
$('#box2').css('display', 'block');
condition = 'block';
});
$('#box2').click(function(e) {
$('#box2').css('display', 'none');
condition = 'none';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box1" style="width: 300px; height: 300px; background-color: red; margin-left: 100px; margin-bottom: 50px; position: absolute;">
</div>
<div id="box2" style="width: 300px; height: 300px; background-color: blue; margin-left: 150px; display: none; position: absolute;">
</div>
This current code works correctly the first time but after that, it wont run again. I am just wondering if there is a reset function or where I am going wrong?
Really what I want to do is make this work on an ipad so when the user clicks/taps away from the box, it will close. If there are better ways to do this on the Ipad tablet, please let me know!!
Any ideas?
Don't overcomplicate things. This is all the javascript you need, get rid of everything else:
$(document).click(function () {
$('#box2').hide();
});
$('#box1').click(function (e) {
e.stopPropagation();
$('#box2').show();
});
You could just filter event target at document level:
$(document).on('click', function(e) {
$('#box2').toggle(!!$(e.target).closest('#box1').length);
});
-jsFiddle-
You can listen to all click events of the document and then use the event.target to detect which element is being clicked. if the clicked element is box1 and box2 is not being shown then display it to the user. in any other condition we can hide the box2 if it's not the element being clicked. here is the vanilla JavaScript code to achieve this:
<html>
<body>
<div id='box1'>BOX ONE</div>
<div id='box2' style="display: none;">BOX TWO</div>
<script>
document.addEventListener('click', function(event) {
var secondBox = document.getElementById('box2')
if(event.target.id === 'box1' && secondBox.style.display === 'none'){
secondBox.style.display = 'block'
} else if (event.target.id !== 'box2') {
secondBox.style.display = 'none'
}
})
</script>
</body>
</html>
And if you are into DRY (Do not repeat yourself), you can define a function for this task. Take look at this modified version of the script:
function addOpenHandler(handler, target){
document.addEventListener('click', function(event) {
if(event.target === handler && target.style.display === 'none'){
target.style.display = 'block'
} else if (event.target !== target) {
target.style.display = 'none'
}
})
}
addOpenHandler( document.getElementById('box1'), document.getElementById('box2') )
$(document).click(function () {
if (condition === 'block')
{
$(":not(#box2)").click(function () {
$("#box2").hide();
});
}
})
The line $("#box2").hide(); is firing after every click

Collapse slideToggle on Click jQuery

I'm currently trying to make a sidebar menu that requires a lot of javascript; making a menu item active in class when clicked, and making it unactive when another item is clicked. The problem I'm having is that some Menu items have submenu items. Now when I click them, using jQuery, they slidetoggle to open, but when I click on another item, they too slideToggle to open. I am trying to make it so that when I click a different item, slidetoggle is undone on the other items
I'm sorry if my english is poor but I hope all understand what I am saying
Here's a jsFiddle
<script>
$(document).ready(function(){
var guts = $('#guts').css('display');
var guts2 = $('#guts2').css('display');
var guts3 = $('#guts3').css('display');
$("#click").click(function(){
$("#guts").slideToggle("fast");
if (guts2 == 'block')
$("#guts2").slideToggle("fast");
if (guts3 == 'block')
$("#guts3").slideToggle("fast");
$(this).addClass("active").siblings('.active').removeClass('active');
});
$("#click2").click(function(){
$("#guts2").slideToggle("fast");
if (guts == 'block')
$("#guts").slideToggle("fast");
if (guts3 == 'block')
$("#guts3").slideToggle("fast");
$(this).addClass("active").siblings('.active').removeClass('active');
});
$("#click3").click(function(){
$("#guts3").slideToggle("fast");
if (guts2 == 'block')
$("#guts2").slideToggle("fast");
if (guts == 'block')
$("#guts").slideToggle("fast");
$(this).addClass("active").siblings('.active').removeClass('active');
});
$("#home").click(function(){
$(this).addClass("active").siblings('.active').removeClass('active');
if (guts == 'block')
$("#guts").slideToggle("fast");
if (guts2 == 'block')
$("#guts2").slideToggle("fast");
if (guts3 == 'block')
$("#guts3").slideToggle("fast");
});
});
</script>
<div id="links">
Home
Staff
<div id="guts">
• Staff List
</div>
Locations
<div id="guts2">
• Location List
</div>
Calendar
</div>
Your variables are out of scope for what you want to happen. You are declaring them globally and when each of your click functions are called it doesn't update the variable, it grabs what the variable was initially was on page load which is 'none'.
Place the variables inside the functions so that it updates those variables when they are called.
Instead of:
var guts = $('#guts').css('display');
var guts2 = $('#guts2').css('display');
var guts3 = $('#guts3').css('display');
$("#click").click(function(){
$("#guts").slideToggle("fast");
if (guts2 == 'block')
$("#guts2").slideToggle("fast");
if (guts3 == 'block')
$("#guts3").slideToggle("fast");
$(this).addClass("active").siblings('.active').removeClass('active');
});
Do:
$("#click").click(function(){
var guts = $('#guts').css('display');
var guts2 = $('#guts2').css('display');
var guts3 = $('#guts3').css('display');
$("#guts").slideToggle("fast");
if (guts2 == 'block') {
$("#guts2").slideToggle("fast");
}
if (guts3 == 'block') {
$("#guts3").slideToggle("fast");
}
$(this).addClass("active").siblings('.active').removeClass('active');
});
Optionally:
var guts, guts2, guts3;
$("#click").click(function(){
guts = $('#guts').css('display');
guts2 = $('#guts2').css('display');
guts3 = $('#guts3').css('display');
$("#guts").slideToggle("fast");
if (guts2 == 'block') {
$("#guts2").slideToggle("fast");
}
if (guts3 == 'block') {
$("#guts3").slideToggle("fast");
}
$(this).addClass("active").siblings('.active').removeClass('active');
});
DEMO
I've rewritten the code using unordered list menu (my favourite for menus). Instead of adding click event to each menu item i've added one event that handles everything ( if you have custom stuff to add to any item, you can just include it using a conditional statement )
HTML:
<ul id="links">
<li>Home</li>
<li>Locations
<ul class="submenu">
<li>Location List</li>
</ul>
</li>
<li>Staff
<ul class="submenu">
<li>Staff List</li>
</ul>
</li>
<li>Calendar</li>
</ul>
Javascript
$(document).ready(function () {
$('#links a').click(function () {
if (!$(this).hasClass('.active')) {
$('.active').removeClass('active');
$(this).addClass('active');
}
if ($(this).hasClass('toggled')) {
$(this).removeClass('toggled');
$(this).next().slideToggle(250);
} else if ($(this).next('ul').length > 0) {
$('.toggled').next().slideToggle(250);
$('.toggled').removeClass('toggled');
$(this).addClass('toggled');
$(this).next().slideToggle(250);
} else if(!$(this).parent().parent().hasClass('submenu')) {
$('.toggled').next().slideToggle(250);
$('.toggled').removeClass('toggled');
}
return false;
})
});
And finally some CSS:
#links,
#links ul{
display: block;
padding: 0;
margin: 0;
list-style: none;
text-align: center;
}
#links a {
display: block;
padding: 1px 0
}
#links a.active {
background-color: rgb(0, 173, 255);
}
#links ul{
display: none
}
Check the DEMO

Categories

Resources