Trigger addClass on mouserover using 'this' - javascript

I am trying to create on hover color change of buttons using javascript code, the unclear part for me is how to set up 'this' attribute so the hovered element trigger the css part for specific button.
$('this').mouseover(function() {
$('#div').removeClass('svg-active');
$('#span').removeClass('light-blue-link');
});
$('this').mouseout(function() {
$('#div').removeClass('svg-active');
$('#span').removeClass('light-blue-link');
});
.button-outer {
margin-top: 30px;
}
.button {
height: 30px;
width: auto;
cursor: pointer;
z-index: 1;
}
.button::before {
display:inline-block;
content:'';
height: 100%;
vertical-align: middle;
}
.light-blue-link {
color: rgb(88, 202, 230);
}
span {
font-weight: 300;
transition: color 1s ease;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='button-outer'>
<div class='button'>
<div id='div' class='svg profile'></div>
<span id='span' class=''>Profile</span>
</div>
<div class='button'>
<div id='div' class='svg friends'></div>
<span id='span' class=''>Friends</span>
</div>
<div class='button'>
<div id='div' class='svg timeline'></div>
<span id='span' class=''>Timeline</span>
</div>
<div class='button'>
<div id='div' class='svg messages'></div>
<span id='span' class=''>Messages</span>
</div>
<div class='button'>
<div id='div' class='svg bookmarks'></div>
<span id='span' class=''>Bookmarks</span>
</div>
</div>

Note: First I address the JavaScript/jQuery question, but note the "However" bit at the end — you don't need them at all for this.
Instead of 'this' you want .button or div.button.
But that's not the main problem.
The main problem is that you're using the same id on more than one element. You can't do that, it's invalid, and browsers will typically use the first element and ignore the id on the other ones.
You don't need ids on those at all. Within your handlers, this will refer to the element you hooked the event on, so you can use the fact that the div and span are inside the element (via find) to find them:
$('div.button').mouseover(function() {
var $this = $(this);
$this.find('div').removeClass('svg-active');
$this.find('span').removeClass('light-blue-link');
});
$('div.button').mouseout(function() {
var $this = $(this);
$this.find('div').removeClass('svg-active');
$this.find('span').removeClass('light-blue-link');
});
Updated example:
$('div.button').mouseover(function() {
var $this = $(this);
$this.find('div').addClass('svg-active');
$this.find('span').addClass('light-blue-link');
});
$('div.button').mouseout(function() {
var $this = $(this);
$this.find('div').removeClass('svg-active');
$this.find('span').removeClass('light-blue-link');
});
.button-outer {
margin-top: 30px;
}
.button {
height: 30px;
width: auto;
cursor: pointer;
z-index: 1;
}
.button::before {
display: inline-block;
content: '';
height: 100%;
vertical-align: middle;
}
.light-blue-link {
color: rgb(88, 202, 230);
}
span {
font-weight: 300;
transition: color 1s ease;
}
<div class='button-outer'>
<div class='button'>
<div class='svg profile'></div>
<span class=''>Profile</span>
</div>
<div class='button'>
<div class='svg friends'></div>
<span class=''>Friends</span>
</div>
<div class='button'>
<div class='svg timeline'></div>
<span class=''>Timeline</span>
</div>
<div class='button'>
<div class='svg messages'></div>
<span class=''>Messages</span>
</div>
<div class='button'>
<div class='svg bookmarks'></div>
<span class=''>Bookmarks</span>
</div>
</div>
<!-- Scripts at the bottom unless you have a good reason to do something else -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I also changed the calls in your mouseover callback to addClass rather than removeClass.
Other things to consider:
You could use event delegation rather than hooking the event on the buttons directly:
$(".button-outer").on("mouseover", ".div.button", function() {
// ...
});
You could toggle a class on the button itself rather than on the things inside it, and then use structural CSS to apply the styling
However, you don't need JavaScript for this at all: Just use a div.button:hover div rule and a div.button:hover span rule:
.button-outer {
margin-top: 30px;
}
.button {
height: 30px;
width: auto;
cursor: pointer;
z-index: 1;
}
.button::before {
display: inline-block;
content: '';
height: 100%;
vertical-align: middle;
}
div.button:hover span {
color: rgb(88, 202, 230);
}
span {
font-weight: 300;
transition: color 1s ease;
}
<div class='button-outer'>
<div class='button'>
<div class='svg profile'></div>
<span class=''>Profile</span>
</div>
<div class='button'>
<div class='svg friends'></div>
<span class=''>Friends</span>
</div>
<div class='button'>
<div class='svg timeline'></div>
<span class=''>Timeline</span>
</div>
<div class='button'>
<div class='svg messages'></div>
<span class=''>Messages</span>
</div>
<div class='button'>
<div class='svg bookmarks'></div>
<span class=''>Bookmarks</span>
</div>
</div>
<!-- Scripts at the bottom unless you have a good reason to do something else -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

In jQuery, Argument as a string inside $() is a selector. It's failing due to jQuery method look out for element / tag in your DOM like below and One more below is invalid tag.
<this></this>
Try with valid selector like $('div.button')
Note: ID is for unique identifier. please use once. its not semantic if you use multiple times.
Efficient way will be from CSS. Main benefit will mouseout case will be taken care by browser.
div.button:hover {
color: blue;
font-size: 27px;
width:100px;
}

Related

Simple javascript click to add class not working

I am trying to add / remove a class on an element that is clicked liek this
function myFunction() {
this.classList.add("myclass");
}
#first {
height: 100px;
width: 100px;
background: yellow;
color: black;
}
.myclass {
background: red;
color: white;
}
<div id="first" onclick="myFunction(this)">
Click
<div class="second">
</div>
<div class="third">
</div>
</div>
Why is this not working?
You need to pass reference this into function too like:
function myFunction(el) {
el.classList.add("myclass");
}
#first {
height: 100px;
width: 100px;
background: yellow;
color: black;
}
.myclass {
background: red!important;
color: white!important;
}
<div id="first" onclick="myFunction(this)">
Click
<div class="second">
</div>
<div class="third">
</div>
</div>
PS. add !important into css
Pass the this to the defined function too and check the existence of the class. Try this.
function myFunction(el) {
if(!el.classList.contains("myclass")) {
el.classList.add("myclass");
console.log("added");
} else {
el.classList.remove("myclass");
console.log("removed");
}
}
#first {
height: 100px;
width: 100px;
background: yellow;
color: black;
}
.myclass {
background: red;
color: white;
}
<div id="first" onclick="myFunction(this)">
Click
<div class="second">
</div>
<div class="third">
</div>
</div>
It doesn't work because this for inline handlers works differently. You can use .call, and that works... but that's still not good.
function myFunction() {
this.classList.add("myclass");
}
#first {
height: 100px;
width: 100px;
background: yellow;
color: black;
}
.myclass {
background: red !important;
color: white;
}
<div id="first" onclick="myFunction.call(this)">
Click
<div class="second">
</div>
<div class="third">
</div>
</div>
You should avoid inline script altogether and also avoid id selectors in CSS.
Change your id selector to a class selector and change your inline handler to an event listener.
Also, stray strings like "content" are a real pain as your project grows in size. Wrap them in a <span>
const myButton = document.querySelector(".first");
myButton.addEventListener("click", ({
target
}) => target.classList.add("myclass"))
.first {
height: 100px;
width: 100px;
background: yellow;
color: black;
}
.myclass {
background: red;
color: white;
}
<div class="first">
<span>Click</span>
<div class="second"></div>
<div class="third"></div>
</div>
You are facing 2 issues :
you pass this as a parameter to the onclick event, but don't get it in the function definition (), so you can fix it like below ;
id selector is more specific than class selector, so it always take precedence. You can use a class instead of an id for first div, and then your css rule works :)
function myFunction(el) {
el.classList.add("myclass");
}
.first {
height: 100px;
width: 100px;
background: yellow;
color: black;
}
.myclass {
background-color: red;
color: white;
}
<div class="first" onclick="myFunction(this);">
Click
<div class="second">
</div>
<div class="third">
</div>
</div>

How to show only one div at the time?

I've got three sections, inside of which there are two divs. Inside the first one I have a button and after clicking it I should have the next one opened. However, only one div should be visible at the time (so when you click the next one, previous one should be closed). And I've got this functionality, but after clicking on the button again - it doesn't close the corresponding div.
I set up an example of my problem on codepen:
https://codepen.io/hubertstrawa/pen/abOwWMJ
<section>
<div class="product">
<span class="btn">Show more</span>
<p>Lorem ipsum</p>
</div>
<div class="product-more displayNone">
Test
</div>
</section>
$('.btn').click(function(e) {
// only one div to be shown but can't be closed as well.
$('.product-more').each(function(i, v) {
$(this).removeClass('displayBlock');
$(this).addClass('displayNone');
})
if ($(e.target).parent().next().hasClass('displayNone')) {
$(e.target).parent().next().removeClass('displayNone');
$(e.target).parent().next().addClass('displayBlock');
} else {
$(e.target).parent().next().removeClass('displayBlock');
$(e.target).parent().next().addClass('displayNone');
}
});
Any ideas how can I make it work?
Thank you
Change a .is-open on a parent element.
<section class="product is-open"> <!-- is-open toggled by JS -->
<div class="product-more"></div> <!-- handle children styles using CSS -->
</section>
.product-more { display: none; } /* default */
.product.is-open .product-more { display: block; } /* when ancestor is .is-open*/
Use delegateTarget inside the .on() method to get back the .product delegator element
const $product = $('.product'); // Collect all current products
$product.on('click', '.btn', function(e) {
const $thisProd = $(e.delegateTarget); // The .product delegator
$product.not($thisProd).removeClass('is-open'); // Handle all (but not this)
$thisProd.toggleClass('is-open'); // Handle current
});
/* QuickReset */ * {margin: 0; box-sizing: border-box;}
.product {
background-color: #ededed;
width: 400px;
margin: 0 auto;
margin-bottom: 1rem;
}
.product-title {
position: relative;
padding: 1rem;
}
.product .btn {
position: absolute;
bottom: 0;
right: 0;
padding: .7rem;
background-color: cyan;
cursor: pointer;
}
.product-more {
width: 100%;
padding: 1rem;
background-color: cyan;
display: none; /* by default */
}
.product.is-open .product-more {
display: block;
}
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
This is preferred, since it lets you change HTML and CSS, and not worry any more about JavaScript - whilst by using .prev(), .next() or .parent() (like the other answers suggest) JS is just waiting for you to change the markup - to break.
No need to traverse back and forth your selectors.
No need for .displayNone and .displayBlock on the product-more element.
Handling dynamic .product
if your .product are dynamic elements, here's another solution to the above concept:
$('.allProducts').on('click', '.btn', function(e) {
const $product = $(e.delegateTarget).find('.product'); // Get all .product
const $thisProd = $(this).closest('.product'); // The closest .product ancestor
$product.not($thisProd).removeClass('is-open'); // Handle all (but not this)
$thisProd.toggleClass('is-open'); // Handle current
});
/* QuickReset */ * {margin: 0; box-sizing: border-box;}
.product {
background-color: #ededed;
width: 400px;
margin: 0 auto;
margin-bottom: 1rem;
}
.product-title {
position: relative;
padding: 1rem;
}
.product .btn {
position: absolute;
bottom: 0;
right: 0;
padding: .7rem;
background-color: cyan;
cursor: pointer;
}
.product-more {
width: 100%;
padding: 1rem;
background-color: cyan;
display: none; /* by default */
}
.product.is-open .product-more {
display: block;
}
<div class="allProducts">
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
You can use the toggleClass it will detect your class and change it to another.
In your each function you just need to set all items to be hide and then it will toggle classes for current item.
Codepen
https://codepen.io/nasser-ali-karimi/pen/rNVwwLy?editors=1010
$('.btn').click(function(e) {
// only one div to be shown but can't be closed as well.
$('.product-more').each(function(i, v) {
$(this).removeClass('displayBlock');
$(this).addClass('displayNone');
})
$(e.target).parent().next().toggleClass('displayNone displayBlock');
});
A shorter version using jQuery would be using hide() and toggle():
$('.btn').click(function(e) {
var more = $(e.target).parent().next() ;
$('.product-more').not(more).hide();
$(e.target).parent().next().toggle();
});
You are hiding all the product-more sections when clicking any btn button, and then, trying to show/hide the product-more section associated with the clicked button.
So, when the section product-more is already shown and you click its btn button what happens is that you first hide the associated section and then your code checks if it is not visible and then shows its again.
One possible solution is to discard the associated product-more section when hiding. Also, as divs are shown by default, you don't need the displayBlock class.
$('.btn').click(function(e) {
var $current = $(e.target).parent().next('.product-more');
// Hide all sections that are not the one associated to the current button.
$('.product-more').not($current).addClass('displayNone');
// Show or hide current section.
$current.toggleClass('displayNone');
});

After changing ID of div it still refers to old element (jQuery/JS)

I have three div elements that has a close button (simplified):
<div class="box1" id="box1">
<span>close</span>
</div>
<div class="box2" id="box2">
<span>close</span>
</div>
<div class="box3" id="box3">
<span>close</span>
</div>
If I click the close button, box 1 will be removed via the
jquery removed() function. Consequently, the class of box 2 will be box1, as well as its ID. The same thing goes for the box 3 whose ID and CLASS will become box2.
I used add and remove class, as well as attr('oldID','newID') functions to
achieve this. The problem is, when I try to access the new box 1 (formerly box 2) and use something like $('#box1').fadeOut(), the one that disappears is box 2
(formerly box 3).
Do you know why this happens?
removed() is not a jQuery function. Instead, the jQuery method .remove() is used to remove the set of matched elements from the DOM.
Please, consider the ID must be unique and there is no need to change them. You may simply work on classes.
Consider to avoid global variables and to use data attribute to preserve ordering.
Your jsfiddle can be reduced to:
$('.header').on('click', function(e) {
//
// decide the animation direction....
//
var newBottom = ($(this).closest('.box').css('bottom') == '-180px') ? '0px' : '-180px';
$(this).closest('.box').animate({'bottom':newBottom}, 200);
});
$('.close').on('click', function(e) {
$(this).closest('.box').remove();
$('.close').each(function(idx, ele) {
var classNames = ['', 'second', 'third'];
//
// toggle classes
//
$(this).closest('.box').toggleClass(classNames[this.dataset.sortOrder - 1] + ' ' + classNames[idx]);
var sortOrder = idx + 1;
this.dataset.sortOrder = sortOrder;
//
// adjust titles
//
$(this).prev('.title').text(function(idx, txt) {
return txt.replace(/\d$/, sortOrder)
})
})
});
.box {
background: #ffffff;
height: 200px;
width: 150px;
bottom: 0;
z-index: 10;
right: 30px;
position: fixed;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
box-shadow: -2px 2px 20px #D8D8D8;
}
.second {
right: 200px;
}
.third {
right: 370px;
}
.header {
height: 30px;
width: 200px;
cursor : pointer;
}
.title {
float:left;
background: #53DD6C;
}
.close {
float:right;
cursor : pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="box" id="first-box">
<span class="header" id="first-header">
<span class="title">Box 1</span>
<span class="close" data-sort-order="1" id="first-close">X</span>
</span>
</div>
<div class="box second" id="second-box">
<span class="header" id="second-header">
<span class="title">Box 2</span>
<span class="close" data-sort-order="2" id="second-close">X</span>
</span>
</div>
<div class="box third" id="third-box">
<span class="header" id="third-header">
<span class="title">Box 3</span>
<span class="close" data-sort-order="3" id="third-close">X</span>
</span>
</div>
Looking at your jsfiddle, it looks like a lot of overkill. You should be able to manage each element with one common function.
$('.header').on('click', function() {
// Add or remove the 'expanded' class
$(this).toggleClass('expanded');
var boxId = $(this).attr('id').substring('header-'.length);
// Set up the new bottom for animation
var bottomPx = '-180px';
if ($(this).hasClass('expanded')) {
bottomPx = '0px';
}
$('#' + boxId).animate({'bottom':bottomPx}, 200);
});
$('.close').on('click', function() {
var boxId = $(this).attr('id').substring('close-'.length);
$('#' + boxId).remove();
});
.box {
background: #ffffff;
height: 200px;
width: 150px;
bottom: 0;
z-index: 10;
right: 30px;
position: fixed;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
box-shadow: -2px 2px 20px #D8D8D8;
}
.second {
right: 200px;
}
.third {
right: 370px;
}
.header {
height: 30px;
width: 200px;
cursor : pointer;
}
.title {
float:left;
background: #53DD6C;
}
.close {
float:right;
cursor : pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" id="box1">
<span class="header expanded" id="header-box1">
<span class="title">Box 1</span>
<span class="close" id="close-box1">X</span>
</span>
</div>
<div class="box second" id="box2">
<span class="header expanded" id="header-box2">
<span class="title">Box 2</span>
<span class="close" id="close-box2">X</span>
</span>
</div>
<div class="box third" id="box3">
<span class="header expanded" id="header-box3">
<span class="title">Box 3</span>
<span class="close" id="close-box3">X</span>
</span>
</div>

How to hide various span tags with a known id leaving just one visible

I have this page where I have some span tags that works like a link, inside it I have some hidden divs, what I want to do is when I click in one of these links the div inside of the clicked one is shown and the other spans receive the property display:none.
Like this:
<style>
#divHidden{display:none;}
</style>
<span id="link_01" onclick="myfunction()"> <!--<<= when clicked-->
<div id="divHidden">Content</div> <!--<<= this comes visible-->
</span>
<span id="link_02" onclick="myfunction()"> <!--<<= then this-->
<div id="divHidden">Content</div>
</span>
<span id="link_03" onclick="myfunction()"> <!--<<= and this goes hidden-->
<div id="divHidden">Content</div>
</span>
how do I code this in javascript?
Something like this?
UPDATE: to work as request, hope this is ok
codepen version
$('.content-wrapper').on('click','.tag', function(evt){
evt.preventDefault();
var selectedDiv = $(this).prop('id');
$('.content-wrapper span:not(#' + selectedDiv + ')').hide();
$(this).find('.content').addClass('show');
})
span.tag .content {
padding-top: 10px;
text-align: center;
display: none;
}
span.tag .content.show {
display: block;
}
span.tag {
margin: 0 auto;
padding: 6px 0;
border-bottom: 1px #ddd solid;
width: 200px;
cursor: pointer;
color: #444;
height: 40px;
background: #eee;
transition: background 600ms;
display: block;
}
span.tag:hover {
background: #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content-wrapper">
<span class="tag" id="tag-one">
<div class="content">Content A</div>
</span>
<span class="tag" id="tag-two">
<div class="content">Content B</div>
</span>
<span class="tag" id="tag-thre">
<div class="content">Content C</div>
</span>
</div>

Hidden Element slides between another element

I'm trying to create the same effect as found on this site here https://glenner.org/ in the header when you click either the phone or email icon it toggles hidden text to slide. So when you click on the phone icon the text slides between the phone and the email icon.
I have this so far:
<div id="clickable" style="float:left; cursor:pointer; color: red"><i class="fa fa-phone"></i></div>
<div id="hidden" style="display:none; white-space:nowrap;">Phone Number</div>
<div id="clickable2" style="float:left; cursor:pointer; color: red"><i class="fa fa-envelope"></i></div>
<div id="hidden2" style="display:none; white-space:nowrap;">Email Here</div>
//
$('#clickable').click(function() {
$('#hidden').animate({width:'toggle'},350);
});
$('#clickable2').click(function() {
$('#hidden2').animate({width:'toggle'},350);
});
As of now when I click on one of the links it goes down to the next line, I'm sure I'm missing some css styling to fix this?
Here is my JsFiddle set up for it: http://jsfiddle.net/804jeg82/412/
I would clean up your code a little, put the hidden div inside the clickable div. Use CSS to control the animation and use classes rather than id's.
But that's just personal preference.
$(document).ready(function(){
$('.clickable').on('click' , function() {
$(this).find('.hid').toggleClass('showme');
});
});
.clickable .fa {
cursor: pointer;
color: red
}
.clickable .fa,
.hid {
float: left;
}
.hid {
width: 0;
overflow: hidden;
white-space: nowrap;
transition: all ease .35s;
-webkit-transition: all ease .35s;
-moz-transition: all ease .35s;
}
.showme {
width: 180px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<div class="clickable"><i class="fa fa-phone"></i>
<div class="hid">Phone Number</div>
</div>
<div class="clickable"><i class="fa fa-envelope"></i>
<div class="hid">Email Here</div>
</div>
You need to add float:left to your hidden div
Specifically:
<div id="hidden" style="display:none; white-space:nowrap; float:left">Phone Number</div>
You may also wish to consider separating your HTML and CSS, for example if you used the ID, you could do something like:
HTML
<div id="hidden">Phone Number</div>
CSS
#hidden {
display:none;
white-space:nowrap;
float:left;
}

Categories