I'm adapting this vertical slider for an pessoal project, but when i click into up or down arrow this works but without any animation. I wanted it to happen a up or down glide smooth depending on the clicked button. This the adapted JS:
// JavaScript Document
$(function() {
$("section#canais").hover(function() {
$("section#buttonsubir").fadeIn();
$("section#buttondescer").fadeIn();
}, function(){
$("section#buttonsubir").fadeOut();
$("section#buttondescer").fadeOut();
});
$(".cnext").click(function(e) {
e.preventDefault();
$("section#canais ul").css({'height' : ''}).animate({top:275}, function(){
$("#canais ul li").last().after($("#canais ul li").first());
$(this).css({'down':'0', 'height':'auto'});
});
});
$(".cprev").click(function(e) {
e.preventDefault();
$("#canais ul li").first().before($("#canais ul li").last().css({'top':-275}) );
$("section#canais ul").css({'height':''}).animate({top:275}, function(){
$("#canais ul li").first().css({'margin-left':'0'});
$(this).css({'left':'0', 'height':'auto'});
});
});
});
Here's my JsFiddle. Thanks.
You need to change a few things - first you need the ul to be positioned absolutely:
#left-content #canais-links {
position:absolute;
}
Then you need to fix your jQuery (the animation should be 36px as that is the height of your lis: in your css)
$(".cnext").click(function (e) {
e.preventDefault();
$("section#canais ul").css({
'height': ''
}).animate({
top: 36 + "px"
}, function () {
$("#canais ul li").last().insertBefore($("#canais ul li").first());
$(this).css({
'top': 0
});
});
});
$(".cprev").click(function (e) {
e.preventDefault();
$("section#canais ul").css({
'height': ''
}).animate({
top: -36 + "px"
}, function () {
$("#canais ul li").first().insertAfter($("#canais ul li").last());
$(this).css({
'top': 0
});
});
});
Example
You may want to wrap your ul in a div with a set height and overflow hidden so you can't see the divs once it goes up / down
Updated Fiddle
Another option...which would allow you to display all five items at once would be to use clone() and then remove the hidden element after the animation was completed. An example is here: http://jsfiddle.net/jme11/5Y54k/
I like the approach from Pete a lot but some benefits of this approach is that it uses css for showing and hiding the up and down arrows, reducing your jQuery code and because it's not dependent on positioning, it winds up making your markup and css smaller as well.
HTML:
<div id="left-content">
<div id="img-canais"></div>
UP
<ul id="canais-links">
<li>
Page 1
</li>
<li>
Page 2
</li>
<li>
Page 3
</li>
<li>
Page 4
</li>
<li>
Page 5
</li>
</ul>
DOWN
</div>
CSS:
#left-content {
width: 203px;
}
.direction {
opacity: 0;
transition:opacity .25s linear;
text-align: center;
display: block;
width: 203px;
}
#left-content:hover .direction {
opacity: 1;
}
#canais-links {
list-style: none;
margin: 0 0 25px 0;
padding: 0;
height: 300px;
display:block;
overflow:hidden;
}
#canais-links li {
height: 36px;
width: 100%;
background-color: #253B6B;
display: block;
margin-top: 25px;
}
#canais-links li a {
font-family: Arial, Helvetica, sans-serif;
font-size: 25px;
font-weight: bold;
color: #FFF;
text-decoration: none;
display: block;
height: 36px;
text-align: center;
}
jQuery:
$('.cprev').click(function () {
$('#canais-links li:first-child').clone().insertAfter('#canais-links li:last-child');
$('li:first-child').slideUp('slow', function(){
$('li:first-child').remove();
});
});
$('.cnext').click(function () {
var copieditem = $('#canais-links li:last-child').clone()
copieditem.insertBefore('#canais-links li:first-child').hide();
$('li:first-child').slideDown('slow', function(){
$('li:last-child').remove();
});
});
Related
I'm trying to edit a shopify theme and the last part I'm stuck on is getting these navigation menus to open on hovering instead of clicking. The css I have for the menus is:
.site-nav {
position: relative;
padding: 0;
text-align: center;
margin: 25px 0;
a {
padding: 3px 10px;
}
li {
display: inline-block;
}
}
.site-nav--centered {
padding-bottom: $gutter-site-mobile;
}
/*================ Site Nav Links ================*/
.site-nav__link {
display: block;
white-space: nowrap;
.site-nav--centered & {
padding-top: 0;
}
.icon-chevron-down {
width: 8px;
height: 8px;
margin-left: 2px;
.site-nav--active-dropdown & {
transform: rotateZ(-180deg);
}
}
&.site-nav--active-dropdown {
border: 1px solid $color-border;
border-bottom: 1px solid transparent;
z-index: 2;
}
}
/*================ Dropdowns ================*/
.site-nav--has-dropdown {
position: relative;
}
.site-nav--has-centered-dropdown {
position: static;
}
.site-nav__dropdown {
display: none;
position: absolute;
left: 0;
padding: $dropdown-padding;
margin: 0;
z-index: $z-index-dropdown;
text-align: left;
border: 1px solid $color-border;
background: $color-bg;
left: -1px;
top: 41px;
.site-nav__link {
padding: 4px 30px 4px 0;
}
.site-nav--active-dropdown & {
display: block;
}
li {
display: block;
}
}
// Centered dropdown
.site-nav__dropdown--centered {
width: 100%;
border: 0;
background: none;
padding: 0;
text-align: center;
}
The HTML and Liquid for the header is:
{% if section.settings.align_logo == 'left' %}
<nav class="grid__item medium-up--one-half small--hide" id="AccessibleNav" role="navigation">
{% include 'site-nav' %}
</nav>
{% endif %}
And the relevant menu Javascript:
/* ================ MODULES ================ */
window.theme = window.theme || {};
theme.Header = (function() {
var selectors = {
body: 'body',
navigation: '#AccessibleNav',
siteNavHasDropdown: '.site-nav--has-dropdown',
siteNavChildLinks: '.site-nav__child-link',
siteNavActiveDropdown: '.site-nav--active-dropdown',
siteNavLinkMain: '.site-nav__link--main',
siteNavChildLink: '.site-nav__link--last'
};
var config = {
activeClass: 'site-nav--active-dropdown',
childLinkClass: 'site-nav__child-link'
};
var cache = {};
function init() {
cacheSelectors();
cache.$parents.on('click.siteNav', function(evt) {
var $el = $(this);
if (!$el.hasClass(config.activeClass)) {
// force stop the click from happening
evt.preventDefault();
evt.stopImmediatePropagation();
}
showDropdown($el);
});
// check when we're leaving a dropdown and close the active dropdown
$(selectors.siteNavChildLink).on('focusout.siteNav', function() {
setTimeout(function() {
if ($(document.activeElement).hasClass(config.childLinkClass) || !cache.$activeDropdown.length) {
return;
}
hideDropdown(cache.$activeDropdown);
});
});
// close dropdowns when on top level nav
cache.$topLevel.on('focus.siteNav', function() {
if (cache.$activeDropdown.length) {
hideDropdown(cache.$activeDropdown);
}
});
cache.$subMenuLinks.on('click.siteNav', function(evt) {
// Prevent click on body from firing instead of link
evt.stopImmediatePropagation();
});
}
function cacheSelectors() {
cache = {
$nav: $(selectors.navigation),
$topLevel: $(selectors.siteNavLinkMain),
$parents: $(selectors.navigation).find(selectors.siteNavHasDropdown),
$subMenuLinks: $(selectors.siteNavChildLinks),
$activeDropdown: $(selectors.siteNavActiveDropdown)
};
}
function showDropdown($el) {
$el.addClass(config.activeClass);
// close open dropdowns
if (cache.$activeDropdown.length) {
hideDropdown(cache.$activeDropdown);
}
cache.$activeDropdown = $el;
// set expanded on open dropdown
$el.find(selectors.siteNavLinkMain).attr('aria-expanded', 'true');
setTimeout(function() {
$(window).on('keyup.siteNav', function(evt) {
if (evt.keyCode === 27) {
hideDropdown($el);
}
});
$(selectors.body).on('click.siteNav', function() {
hideDropdown($el);
});
}, 250);
}
function hideDropdown($el) {
// remove aria on open dropdown
$el.find(selectors.siteNavLinkMain).attr('aria-expanded', 'false');
$el.removeClass(config.activeClass);
// reset active dropdown
cache.$activeDropdown = $(selectors.siteNavActiveDropdown);
$(selectors.body).off('click.siteNav');
$(window).off('keyup.siteNav');
}
function unload() {
$(window).off('.siteNav');
cache.$parents.off('.siteNav');
cache.$subMenuLinks.off('.siteNav');
cache.$topLevel.off('.siteNav');
$(selectors.siteNavChildLink).off('.siteNav');
$(selectors.body).off('.siteNav');
}
return {
init: init,
unload: unload
};
})();
Any help would be greatly appreciated. I feel so silly asking a simple question like this. I just can't figure out where to put :hover in the code. It seems pretty strait forward but I can't get it. You can see the site here: AlexandIvy.myShopify.com and the password to view it is staysk. I'm just talking about the top navigation menus.
This is the code from the console:
<nav class="grid__item medium-up--one-half small--hide" id="AccessibleNav" role="navigation">
<ul class="site-nav list--inline " id="SiteNav">
<li class="site-nav--has-dropdown">
<a href="/collections/bedding" class="site-nav__link site-nav__link--main" aria-has-popup="true" aria-expanded="false" aria-controls="SiteNavLabel-bedding">
Bedding
<svg aria-hidden="true" focusable="false" role="presentation" class="icon icon--wide icon-chevron-down" viewBox="0 0 498.98 284.49"><defs><style>.cls-1{fill:#231f20}</style></defs><path class="cls-1" d="M80.93 271.76A35 35 0 0 1 140.68 247l189.74 189.75L520.16 247a35 35 0 1 1 49.5 49.5L355.17 511a35 35 0 0 1-49.5 0L91.18 296.5a34.89 34.89 0 0 1-10.25-24.74z" transform="translate(-80.93 -236.76)"></path></svg>
<span class="visually-hidden">expand</span>
</a>
<div class="site-nav__dropdown" id="SiteNavLabel-bedding">
<ul>
<li>
Sheet Sets
</li>
</ul>
</div>
</li>
Since you're using JS to hide/show the dropdowns, I suggest you do this if you're comfortable with JQuery.
$('.site-nav--has-dropdown').hover(function() {
if ($(this).hasClass('activated')){
$(this).removeClass('activated');
$(this).children('.site-nav__dropdown').css('display', 'none');
}
else{
$(this).addClass('activated');
$(this).children('.site-nav__dropdown').css('display', 'block');
}
});
The idea behind this is that the child closest to .site-nav--has-dropdown which has a class name .site-nav__dropdown can be activated on hover. You can use pol's code too which provides a different (and shorter) approach.
You should use mouseover/mouseout methods in jquery.
$('.site-nav--has-dropdown').mouseover(function() {
$(this).children('.site-nav__dropdown').show();
});
$('.site-nav--has-dropdown').mouseout(function() {
$(this).children('.site-nav__dropdown').hide();
});
Or just use css :hover,
to better support touch devices you should add :focus too.
.site-nav--has-dropdown:hover .site-nav__dropdown,
.site-nav--has-dropdown:focus .site-nav__dropdown {
display: block;
}
jsfiddle demo: sfiddle.net/8p33qh9h
i am new learner of jquery and javaScript.
i want to create a slider with a big image section and a section of thumbs.
slider should slide automatically i have coded so far is working on click or hover but i dont know how to set it on auto please help me how to modify my code. code and slider screen shoot is given below.
slider image
$("document").ready(function()
{
$("#thumbs a").mouseenter(function()
{
var smallimgpath = $(this).attr("href");
$("#bigimage img").fadeOut(function()
{
$("#bigimage img").attr("src",smallimgpath);
$("#bigimage img").fadeIn();
});
return false;
});
});
</script>
#imagereplacement{
border: 1px solid red;
width:98%;
height:400px;
margin:auto;
padding-top:8px;
padding-left:10px;
}
#imagereplacement p{
text-align:inline;
}
#bigimage{
/* border: 1px solid green; */
margin:auto;
text-align:center;
float: left;
}
#thumbs{
/*border: 1px solid yellow;*/
margin: 110px 10px;
text-align:center;
width:29%;
float: right;
}
#thumbs img{
height:100px;
width:100px;
}
//This is where all the JQuery code will go
</head>
<body>
<div id="imagereplacement">
<p id="bigimage">
<img src="images/slider1.jpg">
</p>
<p id="thumbs">
<img src="images/slider1.jpg">
<img src="images/slider2.jpg">
<img src="images/slider3.jpg">
</p>
try with this example, please let me know in case of any more question from you :
$("document").ready(function(){
var pages = $('#container li'),
current = 0;
var currentPage, nextPage;
var timeoutID;
var buttonClicked = 0;
var handler1 = function() {
buttonClicked = 1;
$('#container .button').unbind('click');
currentPage = pages.eq(current);
if ($(this).hasClass('prevButton')) {
if (current <= 0)
current = pages.length - 1;
else
current = current - 1;
nextPage = pages.eq(current);
nextPage.css("marginLeft", -604);
nextPage.show();
nextPage.animate({
marginLeft: 0
}, 800, function() {
currentPage.hide();
});
currentPage.animate({
marginLeft: 604
}, 800, function() {
$('#container .button').bind('click', handler1);
});
} else {
if (current >= pages.length - 1)
current = 0;
else
current = current + 1;
nextPage = pages.eq(current);
nextPage.css("marginLeft", 604);
nextPage.show();
nextPage.animate({
marginLeft: 0
}, 800, function() {});
currentPage.animate({
marginLeft: -604
}, 800, function() {
currentPage.hide();
$('#container .button').bind('click', handler1);
});
}
}
var handler2 = function() {
if (buttonClicked == 0) {
$('#container .button').unbind('click');
currentPage = pages.eq(current);
if (current >= pages.length - 1)
current = 0;
else
current = current + 1;
nextPage = pages.eq(current);
nextPage.css("marginLeft", 604);
nextPage.show();
nextPage.animate({
marginLeft: 0
}, 800, function() {});
currentPage.animate({
marginLeft: -604
}, 800, function() {
currentPage.hide();
$('#container .button').bind('click', handler1);
});
timeoutID = setTimeout(function() {
handler2();
}, 4000);
}
}
$('#container .button').click(function() {
clearTimeout(timeoutID);
handler1();
});
timeoutID = setTimeout(function() {
handler2();
}, 4000);
});
* {
margin: 0;
padding: 0;
}
#container {
width: 604px;
height: 453px;
position: relative;
}
#container .prevButton {
height: 72px;
width: 68px;
position: absolute;
background: url('http://vietlandsoft.com/images/buttons.png') no-repeat;
top: 50%;
margin-top: -36px;
cursor: pointer;
z-index: 2000;
background-position: left top;
left: 0
}
#container .prevButton:hover {
background-position: left bottom;
left: 0;
}
#container .nextButton {
height: 72px;
width: 68px;
position: absolute;
background: url('http://vietlandsoft.com/images/buttons.png') no-repeat;
top: 50%;
margin-top: -36px;
cursor: pointer;
z-index: 2000;
background-position: right top;
right: 0
}
#container .nextButton:hover {
background-position: right bottom;
right: 0;
}
#container ul {
width: 604px;
height: 453px;
list-style: none outside none;
position: relative;
overflow: hidden;
}
#container li:first-child {
display: list-item;
position: absolute;
}
#container li {
position: absolute;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<center>
<h1>HTML Slideshow AutoPlay (Slide Left/Slide Right)</h1>
<br />
<br />
<div id="container">
<ul>
<li><img src="http://vietlandsoft.com/images/picture1.jpg" width="604" height="453" /></li>
<li><img src="http://vietlandsoft.com/images/picture2.jpg" width="604" height="453" /></li>
<li><img src="http://vietlandsoft.com/images/picture3.jpg" width="604" height="453" /></li>
</ul>
<span class="button prevButton"></span>
<span class="button nextButton"></span>
</div>
</center>
Here an example i've created that create an auto slider CodePen Demo and JSFiddle Demo
I've used an object literal pattern to create slide variable just to avoid creating many global function and variable. Inside document.ready i've initialised my slider just by calling slide.init({....}) this way it makes it easy to reuse and work like plugin.
$.extend(slide.config,option)
this code in simple words override you're default configuration defined in config key
as i mentioned in my above comment make a function slider() and place seTimeout(slide,1000) at bottom of your function before closing
Here in this code its done in animate key of slide object it is passed with two parameter cnt and all image array, If cnt is greater then image array length then cnt is set to 0 i.e if at first when cnt keeps on increment i fadeout all image so when i make it 0 the next time the fadeToggle acts as switch
if On then Off
if Off the On
and calling function slider after a delay makes it a recursive call its just one way for continuously looping there are many other ways i guess for looping continuous you can try
well i haven't check if all images Loaded or not which is most important in slider well that you could try on your own.
var slide = {
'config': {
'container': $('#slideX'),
'delay': 3000,
'fade': 'fast',
'easing': 'linear'
},
init: function(option) {
$.extend(slide.config, option);
var imag = slide.getImages();
slide.animate(0, imag);
},
animate: function(cnt, imag) {
if (cnt >= imag.length) {
cnt = 0;
}
imag.eq(cnt).fadeToggle(slide.config.fade, slide.config.easing);
setTimeout(function() {
slide.animate(++cnt, imag);
}, slide.config.delay);
},
getImages: function() {
return slide.config.container.find('img');
}
};
$(document).ready(function() {
slide.init({
'contianer': $('#slideX'),
'delay': 3000,
'fade': 'fast',
'easing': 'swing'
});
})
body {
margin: 0;
padding: 0;
}
.contianer {
width: 100%;
height: 100%;
position: relative;
}
.container > div,
.container > div >img {
width: 100%;
height: 100%;
position: absolute;
z-index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container" id="slideX">
<div id="img1">
<img src="http://imgs.abduzeedo.com/files/articles/magical-animal-photography-gregory-colbert/5.jpg" />
</div>
<div id="img2">
<img src="http://cdn-5.webdesignmash.com/trial/wp-content/uploads/2010/10/great-dog-photography-016.jpg" />
</div>
<div id="img3">
<img src="http://onlybackground.com/wp-content/uploads/2014/01/marble-beautiful-photography-1920x1200.jpg" />
</div>
</div>
Breakfast, starts off as a h4 and ends up with the same styling as the li elements, I was just wondering how to keep it as an h4.
Thanks!
HTML
<div class="recipe">
<h4>Breakfast</h4>
</div>
<div class="content">
<ul>
<li>Banana Berry Crepes - 250 Cals</li>
<li>Strawberry Parfaits - 170 Cals</li>
</ul>
</div>
CSS
.recipe {
cursor: pointer;
}
.content {
display: none;
}
h4 {
font-family: 'proxima_nova_alt_rgbold', sans-serif;
font-size: 30px;
margin: 40px 0 20px 0;
border; solid 4px
}
Javascript
$(document).ready(function(){
$(".recipe").click(function () {
$recipe = $(this);
$content = $recipe.next();
$content.slideToggle(500, function () {
$recipe.text(function () {
return $content.is(":visible") ? "Breakfast" : "Breakfast";
});
});
});
});
check this fiddle
I have changed your JS code as below
$recipe.children('h4').text(function () {
return $content.is(":visible") ? "Breakfast" : "Breakfast";
});
Hope this answered your question :)
i am having a hard time trying to animate this box, so the changes go smooth, but i just cannot figure out how to keep everything together. Help would be really appreciated. (already tried with 'switchClass') Here is the whole code:
<script src="jquery.js"></script>
<script src="http://code.jquery.com/ui/1.10.0/jquery-ui.js"></script>
<style>
#box {
position: relative;
margin: auto;
padding: auto;
display: block;
width: 167px;
height: 167px;
}
#box .item {
position: relative;
margin: 0;
display: block;
width: 100%;
height: 33%;
cursor: pointer;
}
#box .over {
height: 84%;
}
#box .other {
height: 8%;
}
#top {
background: red;
}
#mid {
background: green;
}
#bot {
background: blue;
}
</style>
<script>
function anim(item) {
$('.item').attr('class', 'item other');
$('#' + item.id).attr('class', 'item over');
}
function clean() {
$('.item').attr('class', 'item');
}
</script>
<div id='box' onmouseout="clean()">
<div id='top' class='item' onmouseover='anim(this)'></div>
<div id='mid' class='item' onmouseover='anim(this)'></div>
<div id='bot' class='item' onmouseover='anim(this)'></div>
</div>
edit: this code is running just fine, but its just an example of final output (just some animations needed)
Maybe this is not super cool, but seems to do job:
var $items = $('.item').on({
mouseover: function () {
$items.removeClass('over other');
$items.stop().filter(this).animate({height: '84%'}, function () {
$(this).addClass('over');
})
.end().not(this).animate({height: '8%'}, function () {
$(this).addClass('other');
});
},
reset: function() {
$items.removeClass('over other').stop().animate({height: '33%'});
}
});
$('#box').mouseout(function() {
$items.trigger('reset');
});
http://jsfiddle.net/dfsq/4vnkh/1/
If you want to animate the change, please take a look at jQuery animate
Something like this:
$('.item').mouseenter(function() {
$('.item').animate({
height: 80%
}, 500, function() {
// Animation complete.
});
});
$('.item').mouseleave(function() {
$('.item').animate({
height: 33%
}, 500, function() {
// Animation complete.
});
});
in this case you don't need onmouseout or onmouseover
If your animation is based solely on CSS class attributes why not use CSS3 hover pseudo-selector?
Example:
.box {
width: 200px;
}
.box:hover {
width: 400px;
}
<div class="box">Hover over me!</div>
Additional: Response to comments
If you are looking for custom animation duration you can use a callback function with a duration for the initial function call. Here's an example:
$('#div').animate({
width: '200px',
color: 'blue'
}, 5000, function() {
// Animation finished after 5 seconds.
alert("Animation complete!");
});
Addition #2
Your problem child is this little guy:
$('.item').attr('class', 'item other');
This sets each box to 8% height and THEN expands the primary animating box. Remove this and your #box will remain the same height throughout all animations!
I've built a carousel but I want the buttons to be disabled when the last/first item is in the viewport, i.e. when the last item is visible then disable the 'next' button.
I'm using unbind('click') but it doesn't work.
Please show me the way.
JS:
var MYPROJECT = {
CONTROL: '.controls',
SLIDELIST: '.slide-wrapper ul',
init: function(){
this.projectCarousel();
},
projectCarousel: function(){
var self = this,
jqs_slideList = $(self.SLIDELIST),
slide = jqs_slideList.find('.slide'),
slideWidth = jqs_slideList.find('.slide').outerWidth(true),
firstSlidePos = slide.first().position().left,
lastSlidePos = slide.last().position(),
count = 0;
$(this.CONTROL).on('click', 'a', function (e) {
var thisElm = $(this);
e.preventDefault();
if (thisElm.hasClass('prev')) {/* if prev button is clicked */
jqs_slideList.animate({ marginLeft: '+=' + slideWidth + 'px' });
} else if (thisElm.hasClass('next')) {/* if next button is clicked */
jqs_slideList.animate({ marginLeft: '-=' + slideWidth + 'px' });
count++;
if (count === (slide.length - 1)) {
// disable button
thisElm.unbind('click').css({ /* this should be in css class */
opacity: 0.5,
cursor: 'default'
});
}
}
});
}
};
MYPROJECT.init();
HTML:
<div class="slideshow">
<div class="controls">
-
+
</div>
<div class="slide-wrapper">
<ul>
<li class="slide">
<article>
<h3>Some title here (nav 1)</h3>
<p>Over the past few years, mobile web usage has considerably increased.</p>
</article>
</li>
<li class="slide">
<article>
<h3>Some title here (nav 2)</h3>
<p>Over the past few years, mobile web usage has considerably increased.</p>
</article>
</li>
</ul>
</div>
</div>
CSS:
.slideshow {
margin: 45px auto 0;
width: 318px;
}
.slideshow .slide-wrapper {
width:325px;
padding: 10px;
overflow: hidden;
}
.slideshow ul {
width: 696px;
}
.slideshow .slide {
float: left;
margin-right: 30px;
}
.slideshow .slide article {
background: #fff;
bottom: 0px;
box-shadow: -2px -1px 8px #bbb;
padding: 10px;
width: 298px;
z-index: 5;
}
.controls {
position: relative;
top: 150px;
}
.controls a {
color: #fff;
display: block;
font-size: 36px;
font-weight: bold;
height: 65px;
position: absolute;
text-indent: -9999px;
width: 65px;
}
.controls .prev {
left: -115px;
}
.controls .next {
right: -115px;
}
Many thanks
I would strongly suggest you use some other means to check where you are in your carousel. For instance, you could use the .index from your list instead.
The best way to disable your buttons is by checking the current slide index, and add a disabled class to the control and only animate depending on
Prev: $(".slide").index() > 0
Next: $(".slide").index() < $(".slide-wrapper ul").index() < $(".slide").index()
Here's a JSFiddle example I made for you. There's also a how to create your own plugin that might be good to take into consideration in your project. Just giving you a push in the right direction, good luck!
Here's the code
(function( $ ) {
$.fn.projectCarousel = function(){
var $slides = $(".slide", this),
$current_slide = $(".slide:first-child", this),
$prev = $(".controls a.prev", this),
$next = $(".controls a.next", this);
if($current_slide.index() <= 0) $prev.addClass("disabled");
$prev.click(function(e){
e.preventDefault();
if($current_slide.index() > 0){
if($prev.hasClass("disabled")) $prev.removeClass("disabled");
$(".slide-wrapper ul").animate({ marginLeft: '+=' + $current_slide.outerWidth(true)+ 'px' });
$current_slide = $current_slide.prev();
}
if($current_slide.index() <= 0){
//disable previous
$prev.addClass("disabled");
$next.removeClass("disabled");
}
});
$next.click(function(e){
e.preventDefault();
if($current_slide.index() < $slides.index()){
if($next.hasClass("disabled")) $next.removeClass("disabled");
$(".slide-wrapper ul").animate({ marginLeft: '-=' + $current_slide.outerWidth(true)+ 'px' });
$current_slide = $current_slide.next();
}
if($current_slide.index() >= $slides.index()){
//disable next
$next.addClass("disabled");
$prev.removeClass("disabled");
}
});
}
})( jQuery );
$(".slideshow").projectCarousel();
Array based
Another way is to store each slide element in an array. This approach is very efficient and reliable. The main downside of this approach is that it's a memory hog, but shouldn't be a problem unless you've got alot of slides. It's also very useful, since you can decide which slide # you want to jump to.
An example of an array-based carousel could be done like in this JSFiddle.
Basically, all the animations are contained within one function _to_slide(index) that takes one argument: "Which frame should I animate to?". Since the array is number based, it is more easily managable and controllable.
Here's the code (Including html and css, changed some to accomodate more functions)
Javascript
(function( $ ) {
$.fn.projectCarousel = function(){
var $slides = $(".slide", this),
$current_slide = $(".slide:first-child", this),
$prev = $(".controls a.prev", this),
$next = $(".controls a.next", this);
if($current_slide.index() <= 0) $prev.addClass("disabled");
$prev.click(function(e){
e.preventDefault();
if($current_slide.index() > 0){
if($prev.hasClass("disabled")) $prev.removeClass("disabled");
$(".slide-wrapper ul").animate({ marginLeft: '+=' + $current_slide.outerWidth(true)+ 'px' });
$current_slide = $current_slide.prev();
}
if($current_slide.index() <= 0){
//disable previous
$prev.addClass("disabled");
$next.removeClass("disabled");
}
});
$next.click(function(e){
e.preventDefault();
if($current_slide.index() < $slides.index()){
if($next.hasClass("disabled")) $next.removeClass("disabled");
$(".slide-wrapper ul").animate({ marginLeft: '-=' + $current_slide.outerWidth(true)+ 'px' });
$current_slide = $current_slide.next();
}
if($current_slide.index() >= $slides.index()){
//disable next
$next.addClass("disabled");
$prev.removeClass("disabled");
}
});
}
})( jQuery );
$(".slideshow").projectCarousel();
HTML
<div class="slideshow">
<div class="controls">
<-
-
<input class='select' type='text' value='1' />
+
->
</div>
<div class="slide-wrapper">
<ul>
<li class="slide">
<article>
<h3>Some title here (nav 1)</h3>
<p>Over the past few years, mobile web usage has considerably increased.</p>
</article>
</li>
<li class="slide">
<article>
<h3>Some title here (nav 2)</h3>
<p>Over the past few years, mobile web usage has considerably increased.</p>
</article>
</li>
<li class="slide">
<article>
<h3>Some title here (nav 3)</h3>
<p>Over the past few years, mobile web usage has considerably increased.</p>
</article>
</li>
<li class="slide">
<article>
<h3>Some title here (nav 4)</h3>
<p>Over the past few years, mobile web usage has considerably increased.</p>
</article>
</li>
<li class="slide">
<article>
<h3>Some title here (nav 5)</h3>
<p>Over the past few years, mobile web usage has considerably increased.</p>
</article>
</li>
<li class="slide">
<article>
<h3>Some title here (nav 6)</h3>
<p>Over the past few years, mobile web usage has considerably increased.</p>
</article>
</li>
</ul>
</div>
</div>
CSS
.slideshow {
margin: 45px auto 0;
width: 318px;
}
.slideshow .slide-wrapper {
width:325px;
padding: 10px;
overflow: hidden;
}
.slideshow ul {
width: 2088px;
}
.slideshow .slide {
float: left;
margin-right: 30px;
}
.slideshow .slide article {
background: #fff;
bottom: 0px;
box-shadow: -2px -1px 8px #bbb;
padding: 10px;
width: 298px;
z-index: 5;
}
.controls {
position: relative;
display: block;
overflow: auto;
clear: both;
text-align: center;
}
.controls a {
color: #fff;
display: block;
font-weight: bold;
height: 18px;
width: 18px;
background-color: #000;
text-decoration: none;
text-align: center;
line-height: 16px;
display: inline-block;
}
input.select{
width: 35px;
text-align: center;
}
a.disabled{
cursor: default;
background-color: #d6d6d6;
}
If you're interested in some theory behind the subject, you could read up on them
linked lists vs vectors vs deques.
Even though most of the links are to C++ libraries, the theory is sound for all programming languages.
Rather than unbinding the click, try the following:
if (count === (slide.length - 1)) {
// disable button
thisElm.addClass('disabled');
} else {
thisElm.removeClass('disabled');
}
Then, inside the main .on('click'...) event handler, you'd check for the disabled class before anything else:
$(this.CONTROL).on('click', 'a', function (e) {
var thisElm = $(this);
e.preventDefault();
if (!thisElm.hasClass('disabled'){
//do the rest inside here
}
});
Without a namesapce you need to pass in the function in order to unbind so you either need to make you function into a call back and pass that in as the second arg to unbind Or you can use a namespace like carousel.click and then just unbind that namespace.