Class issue in jQuery

Hi there,

I am making an image gallery using jQuery. I decided to make it from scratch rather than using a plug-in, but I’m confused about why my code is behaving in an unexpected way.

So I have two sets of thumbnails sitting off screen. The jQuery code selects anchors using the selector (‘.thumbs a’), so every anchor which is the child of an element with the class ‘thumbs’.

As a new thumbnail set is selected, the current set slides of the page, and its class is removed, then the new set slides on and the class ‘thumbs’ is added.

So everthing works with the original set of thumbnails, but once i perform the removeClass/addClass, it seems as though jQuery will not recognise the class change.

Here is the HTML:

<body>
<div id="gallery1">
<div id="main_img"><img /></div>
<div id="com_thumbs">
<ul>
<li><a href="images/comissions/favor_big.jpg"><img src="images/comissions/thumbs/favor.jpg"></a></li>
<li><a href="images/comissions/Glamour.jpg"><img src="images/comissions/thumbs/Glamoura.jpg"></a></li>
<li><a href="images/comissions/zoo1.jpg"><img src="images/comissions/thumbs/zooa.jpg"></a></li>
<li><a href="images/comissions/zoo2.jpg"><img src="images/comissions/thumbs/zoob.jpg"></a></li>
</ul>
</div>
<div id="cos_thumbs">
<ul>
<li><a href="images/costume/Lucia_big.jpg"><img src="images/costume/thumbs/Lucia.jpg"></a></li>
<li><a href="images/costume/mercedes10.jpg"><img src="images/costume/thumbs/mercedes10.jpg"></a></li>
<li><a href="images/costume/mercedes21.jpg"><img src="images/costume/thumbs/mercedes21.jpg"></a></li>
<li><a href="images/costume/mercedes2a.jpg"><img src="images/costume/thumbs/mercedes2a.jpg"></a></li>
</ul>
</div>
</div>
<ul id="navigation">
<li><a href="#" id="commissions">comissions</a></li>
<li><a href="#" id="costume">costume</a></li>
<li><a href="#" id="styling">styling</a></li>
</ul>
</body>

Here’s the css:

body{
	text-align:center;
	}
	
ul{
	padding:0;
	list-style:none;
	}

li{
	display:inline;
	margin:5px;
	}
	
#main_img{
	width:400px;
	height:500px;
	margin:auto;
	}

#main_img img{
	opacity:0;
	filter:alpha(opacity=0);
	}
	
#gallery1{
	width:800px;
	height:600px;
	margin:auto;
	overflow:hidden;
	position:relative;
	}
	
#cos_thumbs, #com_thumbs{
	left:1000px;
	position:absolute;
	width:800px;
	}

And finally the jQuery:

$(function(){
	$('#com_thumbs').animate({'left' : '0'}, 2000).addClass('thumbs');
	var firstImg = $('.thumbs a:first').attr('href');
	$('#main_img img').attr('src', firstImg).animate({'opacity':'1'});
	
	$('#costume').click(function(){
		$('.thumbs').animate({'left' : '1000px'}, 2000, function(){
			$(this).removeClass('thumbs');
		$('#cos_thumbs').animate({'left' : '0'}, 2000).addClass('thumbs');
		});
	return false;
	});
	
	$('.thumbs a').click(function(){
		var thisImg = $(this).attr('href');
		var currentImg = $('#main_img img').attr('src');
		if (thisImg == currentImg){
		} else {
		$('#main_img').fadeOut(function(){
			$('#main_img img').attr('src', thisImg)
			$('#main_img').fadeIn();
		});
		}
	return false;
	});
});

Any help would be great!

Cheers,
Mike

Thanks. You can get the next LI with:


$('.selected').parent().next()

So, using that as a context selector, you can get the next anchor with:


$('a', $('.selected').parent().next());

You can check its length to determine if you’re at the end or not. If there is no next, you can get the first with:


$('li:first a', $('.selected').parent().parent())

Let’s see what can be done. There are only two things that are different in each block of code, one being the gallery that’s seleted, and the other being the related thumbnail.

We can give the function a name that describes its purpose, what it does, such as animateOnClick


function animateOnClick(gallery, thumb) {
    $(gallery).click(function(){
        $('.active').animate({'left' : '1000px'}, 2000, function(){
            $(this).removeClass('active');
        });
        $(thumb).animate({'left' : '0'}, 2000).addClass('active');
        return false;
    });
} 
animateOnClick('#commissions', '#com_thumbs');
animateOnClick('#costume', '#cos_thumbs');
animateOnClick('#styling', '#sty_thumbs');

Thanks for your reply SlickAU,

The first line of the jQuery adds the class ‘.thumbs’:

$('#com_thumbs').animate({'left' : '0'}, 2000)[B].addClass('thumbs')[/B];

I have managed to solve the problem by giving the two separate thumb divs the class of ‘.thumbs’, and having jQuery add the class of ‘.active’ to the thumbs that are actually on screen, so now I have this:

$('#commissions').click(function(){
	$('.active').animate({'left' : '1000px'}, 2000, function(){
		$(this).removeClass('active');
	});
$('#com_thumbs').animate({'left' : '0'}, 2000).addClass('active');
return false;
})
	
$('#costume').click(function(){
	$('.active').animate({'left' : '1000px'}, 2000, function(){
		$(this).removeClass('active');
	});
$('#cos_thumbs').animate({'left' : '0'}, 2000).addClass('active');
return false;
})
	
$('#styling').click(function(){
	$('.active').animate({'left' : '1000px'}, 2000, function(){
		$(this).removeClass('active');
	});
$('#sty_thumbs').animate({'left' : '0'}, 2000).addClass('active');
return false;
})
	
$('.thumbs a').click(function(){
	var thisImg = $(this).attr('href');
	var currentImg = $('#main_img img').attr('src');
	if (thisImg == currentImg){
	} else {
	$('#main_img').fadeOut(function(){
		$('#main_img img').attr('src', thisImg)
		$('#main_img').fadeIn();
	});
	}
return false;
});

which is cool, and it works nicely, but now I have a lot of repeated code, which I don’t like. Not sure yet how to define a function, but I guess that should be the subject of a new post.

Cheers,
Mike

Hey pmw57,

just to say managed to get everything working in the end. A friend of mine showed me a debugging tool in Chrome’s inspector. Turns out I’d just missed a parenthesis somewhere along the line.

Just wanted to thank you for all your help with this. It was a great education.

Best,
Mike

With loadMainImg, you can assign the function to a variable, and then call that variable instead.


$(document).keydown(function(e){
    var loadMainImg = function (image) {
        ...
    };
    ...
    loadMainImg(prevImg);
}

So far as recognizing when you’re at the start or end, you can check the length of the prevLink (or nextLink) variable. If it’s empty then jQuery didn’t find one, so you know that no more of that type exists.

Thanks for that, brilliant! :smiley:

So, this is where I’m at right now:


$(document).keydown(function(e){
		if (e.keyCode == 37) {
			var prevImg = $('a', $('.selected').parent().prev()).attr('href');
			var prevLink = $('a', $('.selected').parent().prev());
			$('.selected').stop(true,true).fadeTo(1000, 0.5).removeClass('selected');
			prevLink.addClass('selected').stop(true,true).fadeTo(1000, 1);
			$('#main_img').stop(true,true).fadeOut(function(){
				$('#main_img img').attr('src', prevImg)
				$('#main_img').fadeIn();
			});
			return false;
		} else {}
		if (e.keyCode == 39) {
			var nextImg = $('a', $('.selected').parent().next()).attr('href');
			var nextLink = $('a', $('.selected').parent().next());
			$('.selected').stop(true,true).fadeTo(1000, 0.5).removeClass('selected');
			nextLink.addClass('selected').stop(true,true).fadeTo(1000, 1);
			$('#main_img').stop(true,true).fadeOut(function(){
				$('#main_img img').attr('src', nextImg)
				$('#main_img').fadeIn();
			});
			return false;
		} else {}
	});

This is what I’m using to move around my thumbs with the arrow buttons, and it works fine. Until I get to the start or the end of the list, and then it breaks.

I know how to find the length of the list:


var thumbLength = $('.active ul li').length;

…but I don’t know how to use that to trigger an event when I’ve reached the end of the list, and I don’t know how to return a value that represents where I am in the list.

Finally, my code is beginning to get repetitive again, and I want to find a way to slim it down.

I tried to write a function loadMainImg:


function loadMainImg(image){
  $('#main_img').stop(true,true).fadeOut(function(){
    $('#main_img img').attr('src', image)
    $('#main_img').fadeIn();
  });
});

and then drop it into my code like so:


$(document).keydown(function(e){
		if (e.keyCode == 37) {
			var prevImg = $('a', $('.selected').parent().prev()).attr('href');
			var prevLink = $('a', $('.selected').parent().prev());
			$('.selected').stop(true,true).fadeTo(1000, 0.5).removeClass('selected');
			prevLink.addClass('selected').stop(true,true).fadeTo(1000, 1);
			[b]loadMainImg(prevImg);[/b]
			return false;
		} else {}

but no joy… Is there such a thing as a global function in javascript??

Many thanks,
Mike

Brilliant! Works a treat! Thanks to you both! :slight_smile:

Is the rest of your code that starts with:
$(‘.thumbs a’).click(function(){
still in there too?

If all else fails, put up a test page somewhere so that we can take a look at things for you.

Once again thanks for your help with the function syntax, that was a great lesson. :smiley:

I have added a few bells and whistles to the gallery, with some fade animation on the thumbnails, and the first image from each thumb-block fading in once the thumbnails have finished their animation.

Another problem has presented itself now though…

I would like to move through the thumbnails with the left and right arrow keys.

I have found out that I can catch the events using .keydown() like so:


$(document).keydown(function(e){
		if (e.keyCode == 37) {
			alert( 'left pressed' );
			return false;
		} else {}
		if (e.keyCode == 39) {
			alert( 'right pressed' );
			return false;
		} else {}
	});

But I am struggling to select the next/previous anchor in the list.

With my update, I have added the class ‘selected’ to the thumbnail corresponding to the current ‘#main_img img’.

Something like this seems appropriate:
(‘.selected’).prev(); or (‘.selected’).next();

but no joy… I think its because actually, there are no siblings for my anchor, its on its own within a <li> tag. So I need to move from the ‘.selected’ anchor, to its parent (which I guess is the <li>), then to the next sibling (the next <li> element), then to the child of that (my next anchor).

Err… So I tried:

(‘.selcted’).parent().next().child();

but again no joy…

Think I’m missing something fundamental here. :rolleyes:

As always, any help is greatly received.

Best,
Mike

The class name is placed on the anchor. If you can find out the index number of the list item of that anchor, you can then use the eq() method to go to the previous or next one.

Or, you can make use of selectors instead.

Which one to use depends on the overall structure.

Do you have a test page up online, so that we can use some client-side developer tools to experiment with things?

No, that’s my mistake there. Oddz pointed out that the braces below the return false need to be reversed. I’ve corrected my original code, which should help you to get that part of things going.

@pmw57, that’s great Paul, I can see now how the syntax for the function works, it’s a great help. I’ve put it into my script, but it’s not working. Could there be a missing semi-colon somewhere or something?

Here’s what I’ve put into my code:


$(function(){
function animateOnClick(gallery, thumb) {
    $(gallery).click(function(){
        $('.active').animate({'left' : '1000px'}, 2000, function(){
            $(this).removeClass('active');
        });
        $(thumb).animate({'left' : '0'}, 2000).addClass('active');
        return false;
    } 
});
animateOnClick('#commissions', '#com_thumbs');
animateOnClick('#costume', '#cos_thumbs');
animateOnClick('#styling', '#sty_thumbs');
});

I mean, everything looks good to me, but I’m getting no animation or class changes. I wonder if I’ve made a mistake somewhere down the line?

Many thanks,
Mike


$(function() {

	function animateOnClick(gallery, thumb) {
   		$(gallery).click(function(){
   		
       		$('.active').animate({'left' : '1000px'},2000,function() {
            	$(this).removeClass('active');
        	});
        	
       		$(thumb).animate({'left' : '0'}, 2000).addClass('active');
        	return false;
        	
    	}); 
	}
	
	animateOnClick('#commissions', '#com_thumbs');
	animateOnClick('#costume', '#cos_thumbs');
	animateOnClick('#styling', '#sty_thumbs');
	
});

Looks like a curly brace was miss-placed.

Yes sure, please take a look:

www.ameena.co.uk/gallery.html

I got an email with a reply asking to show my html, but it has not appeared on this thread (at this time on my pc anyway), but I shall answer it anyway.

The HTML remains unchanged from the original post on this thread, except that I have added a few more anchors and another gallery. Here it is again:


<body>
<div id="gallery1">
<div id="main_img"><img /></div>
<div id="com_thumbs" class="thumbs">
<ul>
<li><a href="images/comissions/favor_big.jpg"><img src="images/comissions/thumbs/favor.jpg"></a></li>
<li><a href="images/comissions/Glamour.jpg"><img src="images/comissions/thumbs/Glamoura.jpg"></a></li>
<li><a href="images/comissions/zoo1.jpg"><img src="images/comissions/thumbs/zooa.jpg"></a></li>
<li><a href="images/comissions/zoo2.jpg"><img src="images/comissions/thumbs/zoob.jpg"></a></li>
</ul>
</div>
<div id="cos_thumbs" class="thumbs">
<ul>
<li><a href="images/costume/Lucia_big.jpg"><img src="images/costume/thumbs/Lucia.jpg"></a></li>
<li><a href="images/costume/mercedes10.jpg"><img src="images/costume/thumbs/mercedes10.jpg"></a></li>
<li><a href="images/costume/mercedes21.jpg"><img src="images/costume/thumbs/mercedes21.jpg"></a></li>
<li><a href="images/costume/mercedes2a.jpg"><img src="images/costume/thumbs/mercedes2a.jpg"></a></li>
<li><a href="images/costume/mercedes3a.jpg"><img src="images/costume/thumbs/mercedes3a.jpg"></a></li>
<li><a href="images/costume/mercedes5.jpg"><img src="images/costume/thumbs/mercedes5.jpg"></a></li>
<li><a href="images/costume/mercedes6.jpg"><img src="images/costume/thumbs/mercedes6.jpg"></a></li>
<li><a href="images/costume/mercedes6a.jpg"><img src="images/costume/thumbs/mercedes6a.jpg"></a></li>
<li><a href="images/costume/mercedes7.jpg"><img src="images/costume/thumbs/mercedes7.jpg"></a></li>
<li><a href="images/costume/NATW1.jpg"><img src="images/costume/thumbs/NATW1.jpg"></a></li>
<li><a href="images/costume/NATW1a.jpg"><img src="images/costume/thumbs/NATW1a.jpg"></a></li>
<li><a href="images/costume/NATW1b.jpg"><img src="images/costume/thumbs/NATW1b.jpg"></a></li>
<li><a href="images/costume/NATW2.jpg"><img src="images/costume/thumbs/NATW2.jpg"></a></li>
<li><a href="images/costume/NATW4.jpg"><img src="images/costume/thumbs/NATW4.jpg"></a></li>
<li><a href="images/costume/NATW5.jpg"><img src="images/costume/thumbs/NATW5.jpg"></a></li>
<li><a href="images/costume/yohan1.jpg"><img src="images/costume/thumbs/yohan1.jpg"></a></li>
<li><a href="images/costume/yohan2.jpg"><img src="images/costume/thumbs/yohan2.jpg"></a></li>
<li><a href="images/costume/yohan5.jpg"><img src="images/costume/thumbs/yohan5.jpg"></a></li>
<li><a href="images/costume/yohan6.jpg"><img src="images/costume/thumbs/yohan6.jpg"></a></li>
<li><a href="images/costume/yohan7.jpg"><img src="images/costume/thumbs/yohan7.jpg"></a></li>
<li><a href="images/costume/yoni (4).jpg"><img src="images/costume/thumbs/yoni (4).jpg"></a></li>
</ul>
</div>
<div id="sty_thumbs" class="thumbs">
<ul>
<li><a href="images/styling/adrenaline.jpg"><img src="images/styling/thumbs/adrenaline.jpg"></a></li>
<li><a href="images/styling/angle2.jpg"><img src="images/styling/thumbs/angle2.jpg"></a></li>
<li><a href="images/styling/berlin_bag.jpg"><img src="images/styling/thumbs/berlin_bag.jpg"></a></li>
<li><a href="images/styling/brown trout4.jpg"><img src="images/styling/thumbs/brown trout4.jpg"></a></li>
<li><a href="images/styling/brown trout8.JPG"><img src="images/styling/thumbs/brown trout8.JPG"></a></li>
<li><a href="images/styling/NATW (5).jpg"><img src="images/styling/thumbs/NATW (5).jpg"></a></li>
<li><a href="images/styling/NATW (6).jpg"><img src="images/styling/thumbs/NATW (6).jpg"></a></li>
<li><a href="images/styling/NATW.jpg"><img src="images/styling/thumbs/NATW.jpg"></a></li>
<li><a href="images/styling/pink grease2.jpg"><img src="images/styling/thumbs/pink grease2.jpg"></a></li>
<li><a href="images/styling/pink1.jpg"><img src="images/styling/thumbs/pink1.jpg"></a></li>
<li><a href="images/styling/pink2.jpg"><img src="images/styling/thumbs/pink2.jpg"></a></li>
<li><a href="images/styling/popfag.jpg"><img src="images/styling/thumbs/popfag.jpg"></a></li>
<li><a href="images/styling/popmadame.jpg"><img src="images/styling/thumbs/popmadame.jpg"></a></li>
<li><a href="images/styling/popweep.jpg"><img src="images/styling/thumbs/popweep.jpg"></a></li>
<li><a href="images/styling/popx.jpg"><img src="images/styling/thumbs/popx.jpg"></a></li>
<li><a href="images/styling/secretgarden1.jpg"><img src="images/styling/thumbs/secretgarden1.jpg"></a></li>
<li><a href="images/styling/secretgarden2.jpg"><img src="images/styling/thumbs/secretgarden2.jpg"></a></li>
<li><a href="images/styling/smatka1.jpg"><img src="images/styling/thumbs/smatka1.jpg"></a></li>
<li><a href="images/styling/SOCO1.jpg"><img src="images/styling/thumbs/SOCOa.jpg"></a></li>
<li><a href="images/styling/SOCO2.jpg"><img src="images/styling/thumbs/SOCOb.jpg"></a></li>
</ul>
</div>
</div>
<ul id="navigation">
<li><a href="#" id="commissions">comissions</a></li>
<li><a href="#" id="costume">costume</a></li>
<li><a href="#" id="styling">styling</a></li>
</ul>
</body>

Many thanks,
Mike

OK so feeling a little bit stupid, cause this ain’t working and your instructions were simple enough. :rolleyes:

This is what I got:


$(document).keydown(function(e){
		var loadMainImg = function (image, [b]thumbLink[/b]) {
				var prevImg = $('a', $('.selected').parent().prev()).attr('href');
				var prevLink = $('a', $('.selected').parent().prev());
				var nextImg = $('a', $('.selected').parent().next()).attr('href');
				var nextLink = $('a', $('.selected').parent().next());
				$('.selected').stop(true,false).fadeTo(1000, 0.5).removeClass('selected');
				thumbLink.addClass('selected').stop(true,false).fadeTo(1000, 1);
				$('#main_img').stop(true,true).fadeOut(function(){
					$('#main_img img').attr('src', image)
					$('#main_img').fadeIn();
				});
			});
		if (e.keyCode == 37) {
			loadMainImg(prevImg, prevLink);
			return false;
		} else {}
		if (e.keyCode == 39) {
			loadMainImg(nextImg, nextLink);
			return false;
		} else {}
	});

The only difference to what you showed me was the inclusion of thumbLink in the second line of the code quoted above. All the variables are quoted at the start of the function, so I also tried this:

$(document).keydown(function(e){
		var loadMainImg = function (image, thumbLink) {
				$('.selected').stop(true,false).fadeTo(1000, 0.5).removeClass('selected');
				thumbLink.addClass('selected').stop(true,false).fadeTo(1000, 1);
				$('#main_img').stop(true,true).fadeOut(function(){
					$('#main_img img').attr('src', image)
					$('#main_img').fadeIn();
				});
			});
		if (e.keyCode == 37) {
			var prevImg = $('a', $('.selected').parent().prev()).attr('href');
			var prevLink = $('a', $('.selected').parent().prev());
			loadMainImg(prevImg, prevLink);
			return false;
		} else {}
		if (e.keyCode == 39) {
			var nextImg = $('a', $('.selected').parent().next()).attr('href');
			var nextLink = $('a', $('.selected').parent().next());
			loadMainImg(nextImg, nextLink);
			return false;
		} else {}
	});

but still no joy.

I haven’t got to checking for the length of the variable yet, but I’m pretty confident about that.

Yours gratefully,
Mike

I don’t see anywhere in the HTML code that you provided any element which has the class of “thumbs”. Should’nt you be referencing “#com_thumbs a:first” instead?