JQuery - Not Switching Classes - javascript

It is late so I hope that I am missing something simple.
I have a div that uses a font-awesome fa-plus symbol. If clicked I want it to change to fa-minus and vice versa.
There is an additional class, add-team||remove-team, which is what the click event runs on.
It will change from + to - but not back to + when clicked a second time.
I have also done it from - to + and it doesn't change back to -.
Here is my div:
<div class="col-1 fa fa-plus add-team"></div>
And here are my simple jQuery lines:
$(".add-team").click(function () {
$(this).addClass("fa-minus remove-team").removeClass("fa-plus add-team");
});
$(".remove-team").click(function () {
$(this).addClass("fa-plus add-team").removeClass("fa-minus remove-team");
});
Hope that I'm just missing something simple. Thanks.

The problem is that your event listeners are only set to listen to elements that currently have those classes. The listeners do not dynamically change when the element's classes change. So since the element starts with add-team only the add-team listener is going to work.
What you can do is use setup a delegate event listener, a listener that is setup on a parent element that does not change, eg document and run the listeners off of that.
$(document).on('click','.add-team',function(){
//...
});
$(document).on('click','.remove-team',function(){
//...
});
But you can also just use a single event listener and use jQuery's toggleClass() to toggle all the classes in one call
$(this).toggleClass("fa-plus fa-minus add-team remove-team");
Demo
$(".col-1").click(function () {
$(this).toggleClass("fa-plus fa-minus add-team remove-team");
});
.col-1 {
font-size:24px;
font-weight:bold;
}
.fa-plus:after {
content:'+';
}
.fa-minus:after {
content:'-';
}
.add-team {
color:green;
}
.remove-team {
color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="col-1 fa fa-plus add-team"></div>

Related

Add/Remove class on mouseleave

I have a dropdown Menu opening on click and when the font-awesome fa-bars icon is clicked the fa-bars class is removed and then the font-awesome fa-times class is added.
I also have a mouseleave function that closes the dropdown container when your mouse exits. My question is to see if I can have the icon class change from fa-times to fa-bars on mouseleave.
This is the code that changes the icon on click
<i id="toggleMega" class="fa fa-bars megaNavIcon"></i>
$('#toggleMega').click(function(){
var ele = $('.megaNavIcon');
if(ele.hasClass('fa-bars')){
ele.removeClass('fa-bars')
.addClass('fa-times')
}
else{
ele.addClass('fa-bars')
.removeClass('fa-times')
}
});
This is the code that closes the container on mouseleave
$('.megaNav').on('mouseleave', function() {
$(".megaNav").collapse("hide");
});
Just add the the removeClass() and addClass() methods inside your mouseleave function like this:
$('.megaNav').on('mouseleave', function() {
$(".megaNav").collapse("hide");
$('#toggleMega').removeClass('fa-times');
$('#toggleMega').addClass('fa-bars');
});
Or you can simplify this further by using the toggleClass() method like this:
$('.megaNav').on('mouseleave', function() {
$(".megaNav").collapse("hide");
$('#toggleMega').toggleClass(function(){
return $(this).hasClass('fa-times') ? 'fa-bars' : '';
});
});
CSS should be your first choice for UI/layout functionality. A simple .myclass:hover{} rule is a super easy way to highlight items on mouseenter mouseleave events.
li:hover {
font-weight: bold;
cursor: pointer;
}
<ul>
<li>Foo</li>
<li>Bar</li>
<li>Boo</li>
<li>Yah</li>
<ul>

Popover click event does not work

$('.pop').each(function () {
var $elem = $(this);
$elem.popover({
placement: 'auto',
trigger: 'hover',
html: true,
container: $elem,
animation: true,
content: function () {
var pop_dest = $(this).attr("data-pop");
//console.log(plant);
return $("#"+pop_dest).html();
}
});
});
$('#english').click(function() { // ---> THIS PART DOES NOT WORK
alert("english");
});
$('#turkce').click(function() { // ---> THIS PART DOES NOT WORK
console.log("turkce");
});
I have 2 button in popover. But their click event does not work. How can I fire click event from button click ? My html code is below.
<li>
<a href="javascript: void(0);" id="languages" class="pop" data-html="true" data-toggle="popover" data-pop="popper-content" class="popper">
<?=$language["languages"]?>
</a>
<div class="hide" id="popper-content">
<ul class="lang-list">
<li class="en">
<button id="english">English</button>
</li>
<li class="tr">
<button id="turkce">Türkçe</button>
</li>
</ul>
</div>
</li>
When you call the click function, the buttons are not added to to page yet (since they are in a dynamically added popover) so you have to use something that takes care of future added content:
$('body').on('click', '#english', function () {
alert("english");
});
You should delegate the event to make sure the event get's to the desired DOM element if it's not present at the time the js gets executed:
$("body").on('click', '#english', function() {
alert("english");
});
$("body").on('click', '#turkce', function() {
alert("turkce");
});
You can delegate events with jquery by using the on method, where the selector is the parent node that will delegate the event to the children, the firs parameter is the event name click, the second is the child you want the event to be delegated to #english and the third parameter is the handler.
The content of the popover is dynamically appended to the page. This means that when you attempt to attach the event handlers when the page loads neither of the buttons exist in the DOM. To fix the problem use a delegated event handler:
$(document).on('click', '#english', function() {
alert("english");
}).on('click', '#turkce', function() {
console.log("turkce");
});
The problem is that <button> has a default type of submit. You don't want that default behavior since you provided your own click handler. You need buttons of type="button".
<button id="english" type="button">English</button>

Prevent CSS :hover style propagation

In the following example, when I mouse over the 'X' button, the list-item hover style gets enabled as well, I do not want this to happen.
Is it possible to have a hover style on the button independent of the hover style on the list-group-item? Something like prevent the 'hover' propagation?
Is there any other way to achieve that? Maybe assembling all of this HTML/CSS/JS in a different way?
Working sample here
<ul class="list-group">
<li class="list-group-item">
Lalalalaiaia
<button class="btn btn-default btn-xs pull-right remove-item">
<span class="glyphicon glyphicon-remove"></span>
</button>
</li>
<li class="list-group-item">
Panananannaeue
<button class="btn btn-default btn-xs pull-right remove-item">
<span class="glyphicon glyphicon-remove"></span>
</button>
</li>
</ul>
CSS
.list-group-item:hover {
background: #fafafa;
cursor: pointer;
}
JavaScript
$('.list-group-item').on('click', function(){
console.log('clicked item');
});
$('.remove-item').on('click', function(e){
console.log('clicked remove-item btn');
e.stopPropagation();
});
UPDATE
The problem seems to be that when hovering the inner X button, the mouse actually doesn't leave the 'list-group-item' element, thus, it keeps the hover state.
I was able to solve it by manually dispatching mouseenter and mouseleave on the 'list-group-item' in the mouseleave and mouseenter event of the 'remove-item' button, respectively, without the need to use 'event.stopPropagation()' (except for the button click handler).
The drawback is that I need a mouseenter and a mouseleave event handler for both elements. Preferably I'd use only CSS, but that seems to be impossible.
I'm just not sure whether this is a clean solution, what do you think?
Working sample here
CSS
.list-group-item.mouseover {
background: #fafafa;
cursor: pointer;
}
.list-group-item .remove-item.mouseover {
background: #aaf;
cursor: pointer;
}
JavaScript
// LIST-ITEM EVENT HANDLERS
$('.list-group-item').on('mouseenter', function(e){
$(this).addClass('mouseover');
}).on('mouseleave', function(e){
$(this).removeClass('mouseover');
});
$('.list-group-item').on('click', function(){
console.log('clicked item');
});
// LIST-ITEM REMOVE BUTTON EVENT HANDLERS
$('.remove-item').on('mouseenter', function(e){
$(this).addClass('mouseover');
$(this).parent().mouseleave();
}).on('mouseleave', function(e){
$(this).removeClass('mouseover');
$(this).parent().mouseenter();
});
$('.remove-item').on('click', function(e){
console.log('clicked remove-item btn');
e.stopPropagation();
});
This is impossible to do with CSS only, except the not-so-clean way described by #Pointy.
You can do this with javascript by using event.stopPropagation(). So your hover style should become a class that you toggle on mouseover.
This question is a duplicate of css :hover only affect top div of nest
You can make a negation caluse like Pointy suggests but a more solid solution involves adding an extra node. The idea is that the row and the button become proper siblings since you can't style a TextNode.
<ul class="list-group">
<li class="list-group-item">
<div>Lalalalaiaia</div>
<button class="btn btn-default btn-xs pull-right remove-item">
<span class="glyphicon glyphicon-remove"></span>
</button>
</li>
<li class="list-group-item">
<div>Panananannaeue</div>
<button class="btn btn-default btn-xs pull-right remove-item">
<span class="glyphicon glyphicon-remove"></span>
</button>
</li>
</ul>
Now you can do:
.list-group-item div:hover {
background: #fafafa;
cursor: pointer;
}
You will need some extra trickery to get the button in the right place, like:
// untested
.list-group-item {
position: relative;
}
.list-group-item button {
position: absolute;
top: 5px;
left: 5px;
}
Ok so there is actually a solution that only requires the use of CSS (no HTML or JS stuff)
The following selector will only select those elements with the class "parent" on hover, which do not have a child with the class "child" that is also being hovered on.
.parent:has(:not(.child:hover)):hover {}
The only problem I can see with the :has() selector/pseudo class is browser support (especially older versions) - so before you use it check the currerrent compatibility lists to see if it fits your requirements.
I could not find an answer that worked in all cases, and was also simple to implement. Sadly, there appears to be no consistent solution that is purely CSS and/or requires special arrangements of the HTML.
Here is a jQuery solution that seems to work in all cases.
Any element with .ui-hoverable will receive a .ui-hover class that does not propagate. So you can stack .ui-hoverable elements and only the top-most under the mouse will have the .ui-hover class.
$('.ui-hoverable').each(function() {
var el = $(this);
el.on('mousemove', function () {
var parent = $(event.target).closest('.ui-hoverable');
if(parent.length && parent[0] == el[0]) {
el.addClass('ui-hover');
return;
}
el.removeClass('ui-hover');
});
el.on('mouseleave', function () {
el.removeClass('ui-hover');
});
});
This works because the mousemove event searches for the closest .ui-hoverable and if it is not the current element the .ui-hover is removed. So the top most will receive the .ui-hover and an element under it will have it removed.
Enjoy, report any problems.
Thanks,

jQuery binding events to elements with dynamic class

I have a trigger element and a responding element.
<div class="more"></div>
<div class="info"></div>
I would like to bind an open/close type event.
$('.more').delegate($('.more'), 'click', function(){
$(this).removeClass('more');
$(this).addClass('less');
$(this).text("less...");
$('.info').addClass("open");
});
$('.less').delegate($('.less'), 'click', function(){
$(this).addClass('more');
$(this).removeClass('less');
$(this).text("more...");
$('.info').removeClass("open");
});
It doesn't work as intended, if the second function is nested in the first then you can open and close only once.
If the script is formatted sensibly as above it will open but not close.
Could anyone help me out?
Bonus if the script could support the .info could be either a sibling or the element immediately following $(.more/.less)'s parent.
I've been toying with .on/.live/.bind but less successfully than above.
Use event delegation ,and binded to document or immediate parent,not same element
$(document).on( 'click',".more", function(){
$(this).removeClass('more');
$(this).addClass('less');
$(this).text("less...");
$('.info').addClass("open");
});
$(document).on('click',".less", function(){
$(this).addClass('more');
$(this).removeClass('less');
$(this).text("more...");
$('.info').removeClass("open");
});
DEMO
NOTE: delegate was outdated with latest version of jquery ,so use on instead,
ISSUE: you are delegated with same element $('.less'),$('.more') use immediate parent or document
Just use JavaScript to toggle a class, and let CSS magic do the rest. Here is a demo: http://jsfiddle.net/pomeh/69sX5/1/
And here is the code:
HTML
<div>
Some visible content
</div>
<div class="content-fold">
<div class="more">More...</div>
<div class="less">Less...</div>
</div>
<div class="info">Some hidden additional content</div>
CSS
/* Additional content and Less button hidden by default */
.content-fold + .info, .content-fold .less {
display: none;
}
/* Additional content and Less button shown when class shown is active */
.content-fold.shown + .info, .content-fold.shown .less {
display: block;
}
/* More button hidden when additional content is shown */
.content-fold.shown .more {
display: none;
}
/*
You can also move the "div.info" into the "div.content-fold",
and use ".content-fold.shown > .info" instead of ".content-fold.shown + .info"
Browser support is quite good for adjacent selector (see http://www.quirksmode.org/css/selectors/#t11 and https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_selectors#Browser_compatibility)
*/
JavaScript
$('.content-fold').on('click', function(){
$(this).toggleClass('shown');
});
Use id to do your task. it's easy.
Html
<div class="more" id="toggle"></div>
<div class="info"></div>
Jquery
$('#toggle').click(function(){
var $this = $(this) //store object
if($this.hasClass('more')) {
$this.removeClass('more').addClass('less').text('Less...')
$this.next('.info').addClass('open');
} else {
$this.removeClass('less').addClass('more').text('More...')
$this.next('.info').removeClass('open');
}
});
js Fiddle: http://jsfiddle.net/5N6TL/53/

How do I make this code work for each click?

I have h3 block's and on click of each of the block I am showing the section associated with it. It is actually something like accordion(hide and collapse). I have also given a drop icon to the h3 tags, means that when the block is opened the h3 should have a dropicon pointing downwards while others h3 should have there dropocons towards right. I am controlling this behaviour using backgroundPosition. I am using the jQuery visible condition to see if the particular block is visible then give its drop icon one background position and to the rest other. It works fine but only for first click. It doesn't work for second click; can somebody explain why? Here is my code:
if($(this).next().is(':visible')) {
$(this).css({'backgroundPosition':'0px 14px'});
}
else {
$("h3").css({'backgroundPosition':'0px -11px'});
}
UPDATED CODE:
$("h3").click(function() {
$(".tabs").hide();
$(this).next().show();
if($(this).next().is(':visible')) {
$(this).css({'backgroundPosition':'0px 14px'});
} else {
$("h3").css({'backgroundPosition':'0px -11px'});
}
})
If you wrap the whole block in a div it might make traversing easier.
Html:
<div class="drop-block">
<h3>Click this</h3>
<ul>
<li>Drop</li>
<li>it</li>
<li>like</li>
<li>it's</li>
<li>hot</li>
</ul>
</div>​
Jquery:
var dropper = $('.drop-block');
$(dropper).find('h3').click(function(){
$(this).toggleClass('active');
$(dropper).find('ul').toggle();
});​
Example
I Belive that you are looking for live
So it will be something like this:
$(element).live('click', function(){
if($(this).next().is(':visible')) {
$(this).css({'backgroundPosition':'0px 14px'});
}
else {
$("h3").css({'backgroundPosition':'0px -11px'});
}
}
Instead of editing the css of them, make a css class "open" (or similar), and then add / remove the class on the click to open / close.
It is much easier to debug by checking for the existence of a class than it is to check the css properties of something in JS.
Better make a class name for each situation and easly handle the action
$('h3').on('click', function(){
if($(this).hasClass('opened')) {
$(this).removeClass('opened');
}
else {
$(this).addClass('opened');
}
}
$(document).on('click', 'h3', function(e) {
$(".tabs").hide('slow');
$(this).css({'backgroundPosition':'0px 14px'});
if(!$(this).next().is(':visible'))
{
$("h3").css({'backgroundPosition':'0px -11px'});
$(this).next().show('slow');
}
});
You can remove 'slow' from show/hide if animation is not required
Here is an example.
It sounds like you need to bind click events to the h3 elements and toggle the visibility of the child elements:
$(function(){
$("h3").click(function(){
$(this).next(".tabs").toggle();
});
});
Example markup:
<h3>Item 1</h3>
<div class="tabs">
<h4>Option 1</h4>
<h4>Option 2</h4>
</div>
<h3>Item 2</h3>
<div class="tabs">
<h4>Option 1</h4>
<h4>Option 2</h4>
</div>
Here's a jsFiddle to demonstrate.

Categories

Resources