Here's the Link to the Fiddle.
I'm working with a carousel and I want to make the next/previous buttons functional.
I tried adding the following code but it doesn't update the index properly. Any help would be appreciated!
$($btnNext).click(function (event) {
updateSlides(index + 1);
event.preventDefault();
}
$($btnPrev).click(function (event) {
updateSlides(index - 1);
event.preventDefault();
}
When the click event on those buttons is called, that index variable is undefined. There are several different ways of figuring out the index, the method I used in the fiddle was to set an attribute on the slider and then check it on the click events:
function updateSlides(index, paused) {
$($slider).attr('data-index', index);
...
}
$($btnNext).click(function (event) {
var index = parseInt($('.slider').attr('data-index'));
if(index > $('.slider .content li').length) {
index = 0;
}
console.log('#next', index);
updateSlides(index + 1);
event.preventDefault();
});
$($btnPrev).click(function (event) {
var index = parseInt($('.slider').attr('data-index'));
if(index < 0) {
index = 0;
}
console.log('#previous', index);
updateSlides(index - 1);
event.preventDefault();
});
See the updated fiddle here: http://jsfiddle.net/sbp76sLc/14/
Related
Normally my slideshow goes automatically to the next picture, but I want to detect if it goes backwards by an user-initiated action (keyboard arrows or controls). My solution to this would be to do this (my imaginary code):
if(jQuery("#slideshow article").hasChangedClassFrom("previous").hasChangedClassTo("current")) {
backwards = true;
}
if(backwards) { // code for backwards
jQuery("#slideshow article.previous").css("z-index", "1");
jQuery("#slideshow article.next").css("z-index", "2");
}
else { // code for forwards (normal state)
jQuery("#slideshow article.previous").css("z-index", "2");
jQuery("#slideshow article.next").css("z-index", "1");
}
The classes are already implemented, so that the current slide always has the class "current" and so on. I know this isn't valid code at all, but by reading this, I think it would be quite clear what I want to achieve. I'm not very good at JavaScript/jQuery, but I've tried searching for solutions like this without luck.
Live site // Live JS code
Based on the code from the mentioned link http://dans.no/cycle.js
Declare a variable clickindex=0;
Place the following inside the click function of jQuery("#slideshow nav a").click
clickindex = jQuery("#slideshow nav a").index(this);
if(clickindex<index){
console.log("execute some logic");
}
The jsfiddle link for my solution javascript code http://jsfiddle.net/y601tkfL/
Instead of guessing that the previous class, use the current and the previous index.
http://jsfiddle.net/whyba4L9/5/
UPDATE 2:
var stopp, antall = jQuery("#slideshow article").length;
var index = 0
function slideTo(idx) {
jQuery("#slideshow article, #slideshow nav a").removeAttr("class").filter(':nth-of-type(' + (idx+1) + ')').addClass("current");
if(jQuery("#slideshow article:nth-of-type(2)").hasClass("current")) {
jQuery("#slideshow article:first-of-type").addClass("forrige");
jQuery("#slideshow article:last-of-type").addClass("neste");
}
else if(jQuery("#slideshow article:first-of-type").hasClass("current")) {
jQuery("#slideshow article:last-of-type").addClass("forrige");
jQuery("#slideshow article:nth-of-type(2)").addClass("neste");
}
else if(jQuery("#slideshow article:last-of-type").hasClass("current")) {
jQuery("#slideshow article:nth-of-type(2)").addClass("forrige");
jQuery("#slideshow article:first-of-type").addClass("neste");
}
if(index ==antall-1 && idx ==0 )
{
//lasto to first
}
else if(index>idx || (index == 0 && idx == antall-1))
{
alert('BACKWARDS')
}
index = idx;
};
function startCycle() {
stopp = setInterval(function() {
jQuery("#slideshow article").stop(true, true);
var idx = index + 1 > antall - 1 ? 0 : index + 1;
slideTo(idx,false);
}, 5500);
};
if (antall > 1) {
jQuery("#slideshow").append("<nav>").css("height", jQuery("#slideshow img").height());
jQuery("#slideshow article").each(function() {
jQuery("#slideshow nav").append("<a>•</a>");
}).filter(":first-of-type").addClass("current first");
jQuery("#slideshow article:nth-of-type(2)").addClass("neste");
jQuery("#slideshow article:last-of-type").addClass("forrige");
startCycle();
jQuery("#slideshow nav a").click(function() {
clearInterval(stopp);
startCycle();
var idx = jQuery("#slideshow nav a").index(this);
if (index === idx) return;
slideTo(idx);
}).filter(":first-of-type").addClass("current");
jQuery(document).keyup(function(e) {
if (e.keyCode == 37) {
var idx = index - 1 < 0 ? antall - 1 : index - 1;
slideTo(idx);
clearInterval(stopp);
startCycle();
}
else if (e.keyCode == 39) {
var idx = index + 1 > antall - 1 ? 0 : index + 1;
slideTo(idx);
clearInterval(stopp);
startCycle();
}
});
}
Try calling this function when the user changes the image with parameter of this. I hope I correctly understood what you are asking. If not let me know and I will recode it. Also if the slide show is finished please post your html and javascript.
function whatever(this)
{
if(this.className == 'previous')
{
alert('the user has changed the image');
this.className = 'current';
}
else
{
alert('the user hasn\'t changed the image');
}
}
The dead simplest way to do this, from what I understand your question to aim at, is to put a handler on the index buttons and a method for tracking the current image.
Listen for slide change
var currentSlide = '';
$('.slideIndexButtons').on('click', function(e){
// Conditional logic that compares $(this).data('whichimage') to currentSlide
var whichImage = $(this).data('whichimage');
// ->this means attaching data-whichimage="" to each of the elements, or
// ->you can just stick with detecting the class and going from there
// Either process results in isBackwards boolean
if (currentSlide == 'prev' && whichImage == 'current') {
isBackwards = true;
}
if (isBackwards) {
// Backwards logic here
} else {
// Other logic here
}
// Unless the event we're listening for in keeping currentSlide updated is also fired when
// the slide changes due to user input, we'll need to update currentSlide manually.
currentSlide = whichImage;
});
Track the current slide
$('#slider').on('event', function(){
// This is assuming that we're strictly listening to the slider's automatic sliding
// The event you attach this to is either fired before or after the slide changes.
// Knowing which is key in getting the data you want. You are either getting
// The data from this slide $(this).data('whichimage') or
// $(this).next().data('whichimage')
// Again, you can go with classes, but it is a lot of logic which you have to
// update manually if you ever have to add or alter an image in the slide set.
// Either way, you end up with the variable targetImage
currentSlide = targetImage;
});
With any luck, your slideshow code has an API that will allow you to listen for when slide-related events are fired. Otherwise, you'll have to find a way of setting up, firing and listening for these events manually, either through callbacks passed in or by (eek!) altering the code and possibly unintentionally changing its functionality.
This should give you what you asked for. Let me know how it goes.
You can add this line at the very start of slideTo function in your cycle.js
if((idx < index && !(idx == 0 && index == antall - 1)) ||
(idx == antall - 1 && index == 0)){
jQuery.trigger('BACKWARDS')
}
and then add an event handler for "BACKWARDS" somewhere else convenient (Maybe at the end of cycle.js?).
jQuery.on('BACKWARDS', function(e){
//DO THINGS HERE
}
I wrote a plugin attrchange which I think will effectively solve your problem. attrchange is a simple jQuery plugin to detect an attribute change. The plugin internally uses one of the following compatible methods based on the browser to detect an attribute change,
Mutation Observer
DOMAttrModified
onpropertychange
Try out below demo to understand more about how you can use the plugin for your need.
Click to read more about attrchange.
Note: The plugin doesn't use polling so you can use it without any worries, however polling is supported as an extension to the plugin. You can read more if you are interested.
$('#test').one('click', function() {
$('#test').attrchange({
trackValues: true,
callback: function(event) {
$('#result').html('<div><label>Attribute Name: </label>' + event.attributeName + '</div>' + '<div><label>Old Value</label>' + event.oldValue + '</div>' + '<div><label>New Value</label>' + event.newValue + '</div>');
}
});
//this will toggleClass 'blue-background' every 2 secs
setInterval(function() {
$('#test').toggleClass('lightblue-background');
}, 2000);
});
html {
font-family: Segoe UI, Arial, sans-serif;
font-size: 13px;
}
div#test {
border: 1px solid #d2d2d2;
padding: 10px;
display: inline-block;
}
.lightblue-background {
background-color: #DBEAF9;
}
div label {
font-weight: bold;
margin-right: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://raw.githubusercontent.com/meetselva/attrchange/master/js/attrchange.js"></script>
<div id="test">
<p style="font-weight: bold;">Click anywhere in this box to Start the DEMO</p>
<p>The demo is to simply toggle a class 'lightblue-background' to this div every 2 secs.</p>
<div id="result" style="font-size: 0.9em;"></div>
See the pseudo code for your case using the plugin,
jQuery("#slideshow article").attrchange({
trackValues: true,
callback: function(event) {
if ($(this).hasClass('current') &&
(event.oldValue && event.oldValue.indexOf('previous') >= 0)) {
//code for backward
} else {
//code for forward
}
}
});
I'm using a slideshow on my website using jquery Cycle 1.
I navigate into my slideshow with #next function. when clicking on my last slide of my slideshow it redirect me to another page (var random_next_url_enfant).
I would like to add the spacebar and the right arrow key to navigation inside my slideshow.
when I add this Js code it works, but on the last slide it starts the slideshow again instead of redirecting me to the next page.
$(document.documentElement).keyup(function (e) {
if (e.keyCode == 39)
{
$('#slider_projets').cycle('next');
}
});
here is my full code using the mouse click. on the last slide, it redirects me to another page, it works perfectly. but I would like to get the same with the spacebar and the right arrow :
$('#slider_projets').cycle({
speed: 600, //temps d'animation
timeout: 0, //fréquence
fx: 'scrollLeft',
//compteur//
pager: "#nav",
after: function(currSlideElement, nextSlideElement, options, forwardFlag) {
$('#counter_1').text((options.currSlide + 1) + ' / ' + (options.slideCount));
slideIndex = options.currSlide;
nextIndex = slideIndex + 1;
prevIndex = slideIndex - 1;
if (slideIndex == options.slideCount - 1) {
/*nextIndex = 0;*/
var random_next_url_enfant = $("#random_next_url_enfant").val();
$('#next').on("click", function(e){
e.preventDefault();
window.location = random_next_url_enfant;
});
}
if (slideIndex === 0) {
prevIndex = options.slideCount - 1;
}
}
});
I think i'm missing something but I can't find what !
here is a jsfiddle :
http://jsfiddle.net/8HsdG/
thanks a lot for your help,
You need access to your slider options outside of your slider, the reason you are not getting to the url is because there is no listener telling it to go there, only the click event.
Here is a jsfiddle that will get you very close, it has everything you need, you just have to fill in the blanks.
http://jsfiddle.net/kkemple/8HsdG/1/
I wrapped your code in an anonymous function so I could declare some scoped variables
(function () {
var slideIndex, slideCount;
// all of your code is here
})();
I then added a before call on your slider:
before: function(currSlideElement, nextSlideElement, options, forwardFlag) {
slideCount = options.slideCount;
},
then added the following code to your key events:
if ( slideIndex == slideCount ) {
//redirect to random url
e.preventDefault;
}
#kkemple, I've resolved the problem... I just had to change :
$(document.documentElement).keyup(function (e) {
if (e.keyCode == 32)
{
$('#slider_projets').cycle('next');
}
});
by
$(document.documentElement).keyup(function (e) {
if (e.keyCode == 32)
{
$("#next").trigger("click");
}
});
and it works perfectly ! anyway thanks for your help !
I have this wizard step form that I simulated with <ul> list items by overlapping inactive <li> items with absolute positioning.
The wizard form is working as desired except that I want to hide next or previous button on a certain step.
This is my logic in jQuery but it doesn't do any good.
if (index === 0) {
$('#prev').addClass(invisible);
$('#prev').removeClass(visible);
} else if (index === 1) {
$('#prev').addClass(visible);
$('#prev').removeClass(invisible);
} else {
$('#next').addClass(invisible);
}
To get the index value I used eq() chained on a current step element like the following
var current;
var index = 0;
$(function () {
current = $('.pg-wrapper').find('.current');
$('#next').on('click', function() {
if (current.next().length===0) return;
current.next().addClass('current').show();
current.removeClass('current').hide();
navstep.next().addClass('active');
navstep.removeClass('active');
current = current.next();
navstep = navstep.next();
index = current.eq();
});
I tried to isolate it as much as possible but my full code will give you a better idea.
If you would care to assist please check my JS BIN
There were several issues
you used .eq instead of index
you were missing quotes around the class names
your navigation logic was flawed
no need to have two classes to change visibility
I believe the following is an improvement, but let me know if you have questions.
I added class="navBut" to the prev/next and rewrote the setting of the visibility
Live Demo
var current;
var navstep;
$(function () {
current = $('.pg-wrapper').find('.current');
navstep=$('.nav-step').find('.active');
$('.pg-wrapper div').not(current).hide();
setBut(current);
$('.navBut').on('click', function() {
var next = this.id=="next";
if (next) {
if (current.next().length===0) return;
current.next().addClass('current').show();
navstep.next().addClass('active');
}
else {
if (current.prev().length===0) return;
current.prev().addClass('current').show();
navstep.prev().addClass('active');
}
current.removeClass('current').hide();
navstep.removeClass('active');
current = (next)?current.next():current.prev();
navstep = (next)?navstep.next():navstep.prev();
setBut(current);
});
});
function setBut(current) {
var index=current.index();
var max = current.parent().children().length-1;
$('#prev').toggleClass("invisible",index<1);
$('#next').toggleClass("invisible",index>=max);
}
The eq function will not give you the index, for that you need to use the index() function.
I have not looked at the whole code but shouldn't your class assignemnts look like:
$('#prev').addClass('invisible');
$('#prev').removeClass('visible');
i.e. with quotes around the class names? And is it really necessary to have a class visible? Assigning and removing the class invisible should easily do the job (provided the right styles have been set for this class).
You should make 4 modifications.
1) Use .index() instead of .eq();
2) Add a function changeIndex which changes the class depends on the index and call it on click of prev and next.
3) add quotes to invisible and visible
4) There is a bug in your logic, try going to 3rd step and come back to 1st step. Both buttons will disappear. So you have to make next button visible if index = 0
Here is the demo :
http://jsfiddle.net/ChaitanyaMunipalle/9SzWB/
Use index() function instead of eq() because eq() will return object and index() will return the integer value.
DEMO HERE
var current;
var navstep;
var index = 0;
$(function () {
current = $('.pg-wrapper').find('.current');
navstep=$('.nav-step').find('.active');
$('.pg-wrapper div').not(current).hide();
}(jQuery));
$('#next').on('click', function() {
if (current.next().length===0) return;
current.next().addClass('current').show();
current.removeClass('current').hide();
navstep.next().addClass('active');
navstep.removeClass('active');
current = current.next();
navstep = navstep.next();
index = current.index();
change_step(index)
});
$('#prev').on('click', function() {
if (current.prev().length===0) return;
current.prev().addClass('current').show();
current.removeClass('current').hide();
navstep.prev().addClass('active');
navstep.removeClass('active');
current = current.prev();
navstep = navstep.prev();
index = current.index();
change_step(index)
});
function change_step(value)
{
if (value === 0) {
$('#prev').hide();
$('#next').show();
} else if (value === 1) {
$('#prev').show();
$('#next').show();
} else {
$('#next').hide();
$('#prev').show();
}
}
I have a form spread across multiple divs that are being displayed on and off using jQuery. I would like to disable the next and previous buttons on the first and last div when they are visible.
This sounded like an easy task based on the little that I do know about jQuery but it is proving to be more difficult than I imagined given my current code.
Here are my current next and previous button functions
var sel = "div[data-type='form']";
var current = $(sel).get(0);
$(sel).not(current).hide();
$("#next").click(function () {
if ($(form).valid()) {
current = $(current).next(sel);
$(current).show();
$(sel).not(current).hide();
}
});
$("#prev").click(function () {
current = $(current).prev(sel);
$(current).show();
$(sel).not(current).hide();
});
and here is a fiddle of what is happening at the moment http://jsfiddle.net/GZ9H8/6/
This works (Note: I removed the validation for testing purposes).
$("#next").click(function () {
if (true) {
current = $(current).next(sel);
$(current).show();
$(sel).not(current).hide();
if (!$(current).next(sel).get(0)){
$(this).hide();
}
if ($(current).prev(sel).get(0)){
$("#prev").show();
}
}
});
$("#prev").click(function () {
current = $(current).prev(sel);
$(current).show();
$(sel).not(current).hide();
if ($(current).next(sel).get(0)){
$("#next").show();
}
if (!$(current).prev(sel).get(0)){
$(this).hide();
}
});
Note that the previous button should probably be hidden from the start. Also, you can disable instead of hide if you want.
This may be useful:
$("#next").click(function () {
if ($(form).valid()) {
current = $(current).next(sel);
$(current).show();
$(sel).not(current).hide();
// Last element's index is equal to length - 1
$(this).attr('disabled', current.index(sel) == $(sel).length - 1);
// First element's index is equal to 0
$("#prev").attr('disabled', current.index(sel) == 0);
}
});
$("#prev").click(function () {
current = $(current).prev(sel);
$(current).show();
$(sel).not(current).hide();
// Last element's index is equal to length - 1
$("#next").attr('disabled', current.index(sel) == $(sel).length - 1);
// First element's index is equal to 0
$(this).attr('disabled', current.index(sel) == 0);
});
Regards
I have created a form with malsup's Form Plugin wherein it submits on change of the inputs. I have set up my jQuery script to index drop down menus and visible inputs, and uses that index to determine whether keydown of tab should move focus to the next element or the first element, and likewise with shift+tab keydown. However, instead of moving focus to the first element from the last element on tab keydown like I would like it to, it moves focus to the second element. How can I change it to cycle focus to the actual first and last elements? Here is a live link to my form: http://www.presspound.org/calculator/ajax/sample.php. Thanks to anyone that tries to help. Here is my script:
$(document).ready(function() {
var options = {
target: '#c_main',
success: setFocus
};
$('#calculator').live('submit', function() {
$(this).ajaxSubmit(options);
return false;
});
$(this).focusin(function(event) {
var shiftDown = false;
$('input, select').each(function (i) {
$(this).data('initial', $(this).val());
});
$('input, select').keyup(function(event) {
if (event.keyCode==16) {
shiftDown = false;
$('#shiftCatch').val(shiftDown);
}
});
$('input, select').keydown(function(event) {
if (event.keyCode==16) {
shiftDown = true;
$('#shiftCatch').val(shiftDown);
}
if (event.keyCode==13) {
$('#captured').val(event.target.id);
} else if (event.keyCode==9 && shiftDown==false) {
return $(event.target).each(function() {
var fields = $(this).parents('form:eq(0),calculator').find('select, input:visible');
var index = fields.index(this);
var nextEl = fields.eq(index+1).attr('id');
var firstEl = fields.eq(0).attr('id');
var focusEl = '#'+firstEl;
if (index>-1 && (index+1)<fields.length) {
$('#captured').val(nextEl);
} else if(index+1>=fields.length) {
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(firstEl);
} else {
event.preventDefault();
$(focusEl).focus();
}
}
return false;
});
} else if (event.keyCode==9 && shiftDown==true) {
return $(event.target).each(function() {
var fields = $(this).parents('form:eq(0),calculator').find('select, input:visible');
var index = fields.index(this);
var prevEl = fields.eq(index-1).attr('id');
var lastEl = fields.eq(fields.length-1).attr('id');
var focusEl = '#'+lastEl;
if (index<fields.length && (index-1)>-1) {
$('#captured').val(prevEl);
} else if (index==0) {
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(lastEl);
} else {
event.preventDefault();
$(focusEl).select();
}
}
return false;
});
}
});
});
});
function setFocus() {
with (document.calculator)
var recap = document.getElementById(recaptured.value);
if (recap!=null) {
setTimeout(function() {
if (recap.getAttribute('type')=='text') {
recap.select();
} else {
recap.focus();
}
}, 100 );
}
}
Edit #1: I made a few minor changes to the code, which has brought me a little closer to my intended functionality of the script. However, I only made one change to the code pertaining to the focus: I tried to to disable the tab keydown when pressed on the last element (and also the shift+tab keydown on the first element) in an attempt to force the focus on the element I want without skipping over it like it has been doing. This is the code I added:
$(this).one('keydown', function (event) {
return !(event.keyCode==9 && shiftDown==true);
});
This kind of works. After the page loads, If the user presses tab on the last element without making a change to its value, the focus will be set to the second element. However, the second time the user presses tab on the last element without making a change to its value, and every subsequent time thereafter, the focus will be set to the first element, just as I would like it to.
Edit #2: I replaced the code in Edit #1, with code utilizing event.preventDefault(), which works better. While if a user does a shift+tab keydown when in the first element, the focus moves to the last element as it should. However, if the user continues to hold down the shift key and presses tab again, focus will be set back to the first element. And if the user continues to hold the shift key down still yet and hits tab, the focus will move back to the last element. The focus will shift back and forth between the first and last element until the user lifts the shift key. This problem does not occur when only pressing tab. Here is the new code snippet:
event.preventDefault();
$(focusEl).focus();
You have a lot of code I didn't get full overview over, so I don't know if I missed some functionality you wanted integrated, but for the tabbing/shift-tabbing through form elements, this should do the work:
var elements = $("#container :input:visible");
var n = elements.length;
elements
.keydown(function(event){
if (event.keyCode == 9) { //if tab
var currentIndex = elements.index(this);
var newIndex = event.shiftKey ? (currentIndex - 1) % n : (currentIndex + 1) % n;
var el = elements.eq(newIndex);
if (el.attr("type") == "text")
elements.eq(newIndex).select();
else
elements.eq(newIndex).focus();
event.preventDefault();
}
});
elements will be the jQuery object containing all the input fields, in my example it's all the input fields inside the div #container
Here's a demo: http://jsfiddle.net/rA3L9/
Here is the solution, which I couldn't have reached it without Simen's help. Thanks again, Simen.
$(document).ready(function() {
var options = {
target: '#c_main',
success: setFocus
};
$('#calculator').live('submit', function() {
$(this).ajaxSubmit(options);
return false;
});
$(this).focusin(function(event) {
$('#calculator :input:visible').each(function (i) {
$(this).data('initial', $(this).val());
});
return $(event.target).each(function() {
$('#c_main :input:visible').live(($.browser.opera ? 'keypress' : 'keydown'), function(event){
var elements = $("#calculator :input:visible");
var n = elements.length;
var currentIndex = elements.index(this);
if (event.keyCode == 13) { //if enter
var focusElement = elements.eq(currentIndex).attr('id');
$('#captured').val(focusElement);
} else if (event.keyCode == 9) { //if tab
var newIndex = event.shiftKey ? (currentIndex - 1) % n : (currentIndex + 1) % n;
var el = elements.eq(newIndex);
var focusElement = el.attr('id');
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(focusElement);
} else if ((currentIndex==0 && event.shiftKey) || (currentIndex==n-1 && !event.shiftKey)) {
event.preventDefault();
if (el.attr('type')=='text') {
$.browser.msie ? "" : $(window).scrollTop(5000);
el.select().delay(800);
} else {
$.browser.msie ? "" : $(window).scrollTop(-5000);
el.focus().delay(800);
}
} else if (el.is('select')) {
event.preventDefault();
if (el.attr('type')=='text') {
el.select();
} else {
el.focus();
}
}
}
});
});
});
});
function setFocus() {
with (document.calculator)
var recap = document.getElementById(recaptured.value);
if (recap!=null) {
setTimeout(function() {
if (recap.getAttribute('type')=='text') {
recap.select();
} else {
recap.focus();
}
}, 1 );
}
}
I put my files available to download in my live link: http://www.presspound.org/calculator/ajax/sample.php