This is a bit of a tricky one. I am building a Carousel view, which gets hooked up at loadtime using jQuery.
Here is the mark-up:
<div class="carousel" data-direction="v" id="carousel1">
<div class="card-cont">
<div id="card1" class="card">This is Card 1</div>
<div id="card2" class="card">This is Card 2</div>
<div id="card3" class="card">This is Card 3</div>
<div id="card4" class="card">This is Card 4</div>
</div>
</div>
<div class="carousel" data-direction="h" id="carousel2">
<div class="card-cont">
<div id="card5" class="card">This is Card 1</div>
<div id="card6" class="card">This is Card 2</div>
<div id="card7" class="card">This is Card 3</div>
<div id="card8" class="card">This is Card 4</div>
</div>
</div>
Using jQuery, I loop through all .carousel elements and hook up the functionality. The code is object-oriented, and I have posted some jsFiddle here > http://jsfiddle.net/eZbUB/
The problem is that whenever I have more than one carousel on a page, the events (i.e. changing card) only get applied to the LAST carousel on the page. Does anyone have a solution? The positioning functions for the indicator and sizing etc. all work fine. Here is the full jQuery code:
$(function(){
$('.carousel').each(function() { Carousel.init($(this)); });
});
var Carousel = {
container : null,
card_container : null,
cards : [ ],
card_width : 0,
no_cards : 0,
indicator : { },
current_card : 0,
direction : 'h',
init : function(container) {
// Assin vars:
var self = this;
this.container = container;
this.card_container = this.container.find('.card-cont');
this.cards = this.container.find('div.card');
this.card_width = this.container.width();
this.no_cards = this.cards.length;
this.direction = $(this.container).attr('data-direction');
// Size the container:
this.card_container.width((this.card_width * this.no_cards))
// Add an indicator:
this.indicator = $('<ul class="card-indicator" />');
this.indicator.items = [ ];
if(this.direction == 'v') { this.indicator.addClass('vertical'); }
for(var i = 0; i < this.no_cards; i++)
{
$(this.cards[i]).width(this.card_width);
var indicator_item = $('<li />');
indicator_item.click(function() { self.setCard($(this).index()); });
this.indicator.append(indicator_item);
this.indicator.items.push(indicator_item);
}
this.indicator.appendTo(this.container);
// Position the indicator:
if(this.direction == 'h')
{
var indicator_top_pos = ((this.container.offset().top + this.container.height()) - this.indicator.height());
var indicator_left_pos = (this.container.width() - this.indicator.width()) / 2;
this.indicator.css({ top: indicator_top_pos, left: indicator_left_pos });
}
else
{
var indicator_top_pos = (this.container.height() - this.indicator.height()) / 2;
var indicator_left_pos = (this.container.offset().left + this.container.width()) - 20;
this.indicator.css({ top: indicator_top_pos, left: indicator_left_pos });
}
// Add the current styles to everything:
$(this.cards[0]).addClass('current');
this.indicator.items[0].addClass('current');
// Hook up the drag events:
var mouse_start_x = 0;
var mouse_end_x = 0;
var mouse_start_y = 0;
var mouse_end_y = 0;
var direction_x = null;
var direction_y = null;
var next_index = 0;
this.container.mousedown(function(e) {
mouse_start_x = e.pageX;
mouse_start_y = e.pageY;
});
this.container.mouseup(function(e) {
mouse_end_x = e.pageX;
mouse_end_y = e.pageY;
alert(self.container.attr('id'));
if(mouse_end_x > mouse_start_x) { direction_x = 'right'; }
if(mouse_end_x < mouse_start_x) { direction_x = 'left'; }
if(mouse_end_y > mouse_start_y) { direction_y = 'down'; }
if(mouse_end_y < mouse_start_y) { direction_y = 'up'; }
switch(self.direction)
{
case 'v':
if(direction_y == 'down') { next_index = (self.current_card == 0) ? 0 : self.current_card - 1; }
if(direction_y == 'up') { next_index = (self.current_card == (self.no_cards - 1)) ? self.current_card : self.current_card + 1; }
break;
case 'h':
default:
if(direction_x == 'right') { next_index = (self.current_card == (self.no_cards - 1)) ? self.current_card : self.current_card + 1; }
if(direction_x == 'left') { next_index = (self.current_card == 0) ? 0 : self.current_card - 1; }
break;
}
self.setCard(next_index);
});
// Return the object (we use init as a constructor):
return this;
},
// Function to check if we're on the last card:
onLastCard : function() {
return (this.current_card == (this.indicator.items.length - 1)) ? true : false;
},
// Function to check if we're on the first card:
onFirstCard : function() {
return (this.current_card == 0) ? true : false;
},
setCard : function(index) {
// If the index matches the current one, don't do anything:
if(index == this.current_card)
{
return;
}
else
{
// Calculate the left position we need to move:
var new_left_pos = this.card_width * index;
this.card_container.css({ left: -new_left_pos });
this.indicator.items[this.current_card].removeClass('current');
this.indicator.items[index].addClass('current');
this.current_card = index;
return true;
}
},
};
I have tried other alternatives (such as bind() and live(), but neither has worked). Any help most gratefully received.
The way you’re calling
Carousel.init, withininitfunctionthiswill always beCarousel— that is, there’s only one. That’s why you’re only seeing it get applied to the last.I’d look at reworking
Carouselto be a constructor function (the kind you use withnew). @Boo has just thrown anewin front ofCarousel.init, which is a good start, but the object being created won’t have the various properties you’ve put onCarousel.Here’s a quick reworking; it’s completely untested, but should take you in the right direction:
And then use is:
Again, the above is not meant to be perfect, done, and dusted. It’s to demonstrate how you reformulate
Carouselas a constructor function and set up functions on its prototype so they get assigned to the instances created vianew Carousel. There will be some debugging required. I’m pleased to see you’re already handling the issue ofthiswithin event handlers (via yourselfvariable in what used to beinitand is now theCarouselfunction).Some possibly helpful reading: