Reputation: 434
I have a hidden div that is being toggled. When it appears a span gets its class changed.
$('#websites').click(function(){
$('#webthumbs').slideToggle('fast');
$('#websites span').removeClass('icon-chevron-right').addClass('icon-chevron-down');
$(this).addClass('open');
});
When the div is collapsed and hidden again, I need to change the span's class back to what it was originally. I tried this but it does not work:
$('#websites.open').click(function(){
$('#websites span').removeClass('icon-chevron-down').addClass('icon-chevron-right');
$(this).removeClass('open');
});
I have a feeling the second piece of code is not working because .open
is not in the DOM when the script is loaded. How can I get the second chunk of code to work?
Upvotes: 0
Views: 78
Reputation: 318212
You just need to toggle the classes to toggle the icon
$('#websites').click(function(){
$('#webthumbs').slideToggle('fast');
$('#websites span').toggleClass('icon-chevron-right icon-chevron-down');
});
The reason the code doesn't work, is because event handlers are added to elements matching the selector at execution time, adding the class later makes no difference.
If you need to toggle things that jQuery doesn't provide built-in methods for, you can use a flag
$('#websites').click(function(){
var flag = $(this).data('flag');
if ( flag ) {
// do anything when the state is "open"
$('#webthumbs').slideUp('fast');
} else {
// do anything when the state is "closed"
$('#webthumbs').slideDown('fast');
}
$(this).data('flag', !flag);
});
Upvotes: 2
Reputation: 179056
You can use separate state-based event handlers via event delegation. Instead of binding either event to the #websites
element, bind the event handlers to the nearest stable parent (I'm using 'body'
here, but you may want to use a different selector):
$('body').on('click', '#websites:not(.open)', function () {
...executed when not open...
}).on('click', '#websites.open', function () {
...executed when open...
});
The delegate syntax will allow the click callback to be called on the #websites.open
element despite it not existing in the DOM at the time of binding.
This form is particularly useful when you have significantly different behaviors between the two states.
If you're just toggling everything, I'd recommend making use of jQuery's toggle functions and do it all in one go:
$('#websites').on('click', function () {
$(this)
.slideToggle('fast')
.toggleClass('open')
.find('span')
.toggleClass('icon-chevron-right icon-chevron-down');
});
If you have separate functionality between the two states, you can use a simple if .is
check:
$('#websites').on('click', function () {
if ($(this).is('.open')) {
$(this)
.removeClass('open')
...
} else {
$(this)
.addClass('open')
...
}
});
You can expose callbacks as function references, and toggle which ones are active at any given time:
function openWebsites() {
$(this)
.off('click', openWebsites)
.on('click', closeWebsites)
.addClass('open')
...
}
function closeWebsites() {
$(this)
.off('click', closeWebsites)
.on('click', openWebsites)
.removeClass('open')
...
}
$('#websites').on('click', openWebsites);
Upvotes: 1
Reputation: 3792
open
class is not part of your clicked element, do something.open
class is part of your clicked element, do otherwise.By putting it into words you can see the similarity: Your click event is common among both actuons, this is what needs to happen only once. Within this click event you can use jQuery's hasClass() function to separate the purpose of your click events.
I took the liberty of optimizing your code a little by using caching for your variables. Let me know if you have any questions in the comments below.
JQuery:
$(document).ready(function() {
$('#websites').click(function() {
var websites = $(this),
webthumbs = $("#webthumbs"),
websitesSpan = $("#websites span");
webthumbs.slideToggle('fast');
if (websites.hasClass("open")) {
websitesSpan.removeClass('icon-chevron-down').addClass('icon-chevron-right');
websites.removeClass('open');
} else {
websitesSpan.removeClass('icon-chevron-right').addClass('icon-chevron-down');
websites.addClass('open');
}
});
});
Upvotes: 0
Reputation: 7443
Echoing the previous answers, you could consolidate the two click handlers into one:
$('#websites').click(function() {
if ($(this).hasClass('open')) {
$('#websites span')
.removeClass('icon-chevron-down')
.addClass('icon-chevron-right');
} else {
$('#webthumbs').slideToggle('fast');
$('#websites span')
.removeClass('icon-chevron-right')
.addClass('icon-chevron-down');
}
$(this).toggleClass('open');
});
Upvotes: 0