I am a jQuery (and general programming) learner and rather than using a plug-in I am trying to build my own Image slider/cycle, both to keep the code small, and to aid in learning.
My function cycles through the li items adding a '.show' class, then after a delay removes the class and adds to the next slide. This seems to work fine.
I have been struggling for a few days to add navigation which will either move previous or next and stop the timer.
As it stands, if I click the navigation immediately as the script starts the navigation will work as expected, but once the automatic function to show another slide has started the navigation will jump multiple steps and I have no idea why this is. I imaging somehow jQuery is caching the previous divs which have had a '.show' class perhaps?
I have simplified my code and presentation to illustrate this working up in a CodePen: codepen.io/MattyBalaam/pen/vuhyJ
Here is the complete script:
function gallery(galleryContainer) {
$.fn.nextOrFirst = function(selector) {
var next = this.next(selector);
return (next.length) ? next : this.prevAll(selector).last();
};
$.fn.prevOrLast = function(selector) {
var prev = this.prev(selector);
return (prev.length) ? prev : this.nextAll(selector).last();
};
galleryContainer.parent().prepend('<div class="previous">previous</div><div class="next">next</div>');
var crossFade = function (){
var slideTimeout;
function slideWait() {
galleryContainer.find('.show').removeClass('show').nextOrFirst().addClass('show');
slideTimeout = setTimeout(crossFade, 800);
}
function checkForClicks() {
$('div.previous').on('click', function(){
galleryContainer.find('.show').removeClass('show').prevOrLast().addClass('show');
window.clearTimeout(slideTimeout);
});
$('div.next').on('click', function(){
galleryContainer.find('.show').removeClass('show').nextOrFirst().addClass('show');
window.clearTimeout(slideTimeout);
});
}
checkForClicks();
slideWait();
};
galleryContainer.children(':first-child').addClass('show');
setTimeout(crossFade, 800);
}
gallery($('ul'));
The problem is, that you are calling function checkForClicks multiple times (in each animation iteration) and the event listener is added to buttons multiple times, so on each click you move forwards/backwards not just once, but once for each animation step, that was already displayed. Move the checkForClicks outside the crossFade function and it will be ok.
see the code:
http://codepen.io/anon/pen/ptkea
working code:
function gallery(galleryContainer) {
$.fn.nextOrFirst = function(selector) {
var next = this.next(selector);
return (next.length) ? next : this.prevAll(selector).last();
};
$.fn.prevOrLast = function(selector) {
var prev = this.prev(selector);
return (prev.length) ? prev : this.nextAll(selector).last();
};
galleryContainer.parent().prepend('<div class="previous">previous</div><div class="next">next</div>');
var slideTimeout;
var crossFade = function (){
function slideWait() {
galleryContainer.find('.show').removeClass('show').nextOrFirst().addClass('show');
slideTimeout = setTimeout(crossFade, 800);
}
slideWait();
};
galleryContainer.children(':first-child').addClass('show');
setTimeout(crossFade, 800);
function initButtonEvents() {
$('div.previous').on('click', function(){
galleryContainer.find('.show').removeClass('show').prevOrLast().addClass('show');
window.clearTimeout(slideTimeout);
});
$('div.next').on('click', function(){
galleryContainer.find('.show').removeClass('show').nextOrFirst().addClass('show');
window.clearTimeout(slideTimeout);
});
}
initButtonEvents();
}
gallery($('ul'));
see my script:
http://codepen.io/anon/pen/asvGc
If you declare the var's outside the functions it works fine.
Related
I need some help making a sub-menu appear within 2s after the page loads instead of when the user clicks on it. I'm using JQuery. That file is the core of the website. I need it to stay opened.
Here's the code I have at the moment, I tried to change that on.Click event but it didn't work.
The handleSidenarAndContentHeight(); function resizes the menu items after the sub-menu appears.
jQuery('.page-sidebar li > a').on('click', function (e) {
if ($(this).next().hasClass('sub-menu') === false) {
return;
}
var parent = $(this).parent().parent();
parent.children('li.open').children('a').children('.arrow').removeClass('open');
parent.children('li.open').children('a').children('.arrow').removeClass('active');
parent.children('li.open').children('.sub-menu').slideUp(350);
parent.children('li').removeClass('open');
parent.children('li').removeClass('active');
var sub = jQuery(this).next();
if (sub.is(":visible")) {
jQuery('.arrow', jQuery(this)).removeClass("open");
jQuery(this).parent().removeClass("active");
sub.slideUp(350, function () {
handleSidenarAndContentHeight();
});
} else {
jQuery('.arrow', jQuery(this)).addClass("open");
jQuery(this).parent().addClass("open");
sub.slideDown(350, function () {
handleSidenarAndContentHeight();
});
}
e.preventDefault();
});
Working with a 2 second timeout should do the trick!
jQuery(document).ready(function(){
// Open Parent here
setTimeout(function(){
// Open Child here
}, 2000)
});
There is a simple javascript function you can use, the setTimeout function.
The code follows like this :
setTimeout(function() {yourFunctyion();}. delayTimeInMiliseconds);
This will call your function after the number of second(in ms).
There is also a plugin I've used. It has oneTime and everyTime methods.
jQuery timers plugin
I'm new to javascript and jquery and I am trying to make a video's opacity change when I mouseover a li item. I know 'onmouseover' works because I have tested using the same jquery I use to scroll to the top of the page onclick.
The problem seems to be the syntax to check and update the style of the video div is not working. I adapted the code from a lesson on codeacademy and don't see why it work:
window.onload = function () {
// Get the array of the li elements
var vidlink = document.getElementsByClassName('video');
// Get the iframe
var framecss = document.getElementsByClassName('videoplayer1');
// Loop through LI ELEMENTS
for (var i = 0; i < vidlink.length; i++) {
// mouseover function:
vidlink[i].onmouseover = function () {
//this doesn't work:
if (framecss.style.opacity === "0.1") {
framecss.style.opacity = "0.5";
}
};
//onclick function to scroll to the top when clicked:
vidlink[i].onclick = function () {
$("html, body").animate({
scrollTop: 0
}, 600);
};
}
};
Here is a jsfiddle you can see the html and css:
http://jsfiddle.net/m00sh00/CsyJY/11/
It seems like such a simple problem so I'm sorry if I'm missing something obvious.
Any help is much appreciated
Try this:
vidlink[i].onmouseover = function () {
if (framecss[0].style.opacity === "0.1") {
framecss[0].style.opacity = "0.5";
}
};
Or alternatively:
var framecss = document.getElementsByClassName('videoplayer1')[0];
Or, better, give the iframe an id and use document.getElementById().
The getElementsByClassName() function returns a list, not a single element. The list doesn't have a style property. In your case you know the list should have one item in it, which you access via the [0] index.
Or, given that you are using jQuery, you could rewrite it something like this:
$(document).ready(function(){
// Get the iframe
var $framecss = $('.videoplayer1');
$('.video').on({
mouseover: function () {
if ($framecss.css('opacity') < 0.15) {
$framecss.css('opacity', 0.5);
}
},
click: function () {
$("html, body").animate({
scrollTop: 0
}, 600);
}
});
});
Note that I'm testing if the opacity is less than 0.15 because when I tried it out in your fiddle it was returned as 0.10000000149011612 rather than 0.1.
Also, note that the code in your fiddle didn't run, because by default jsfiddle puts your JS in an onload handler (this can be changed from the drop-down on the left) and you then wrapped your code in window.onload = as well. And you hadn't selected jQuery from the other drop-down so .animate() wouldn't work.
Here's an updated fiddle: http://jsfiddle.net/CsyJY/23/
I've already posted a question about jQuery toggle method here
But the problem is that even with the migrate plugin it does not work.
I want to write a script that will switch between five classes (0 -> 1 -> 2 -> 3 -> 4 -> 5).
Here is the part of the JS code I use:
$('div.priority#priority'+id).on('click', function() {
$(this).removeClass('priority').addClass('priority-low');
});
$('div.priority-low#priority'+id).on('click' ,function() {
$(this).removeClass('priority-low').addClass('priority-medium');
});
$('div.priority-medium#priority'+id).on('click', function() {
$(this).removeClass('priority-medium').addClass('priority-normal');
});
$('div.priority-normal#priority'+id).on('click', function() {
$(this).removeClass('priority-normal').addClass('priority-high');
});
$('div.priority-high'+id).on('click', function() {
$(this).removeClass('priority-high').addClass('priority-emergency');
});
$('div.priority-emergency'+id).on('click', function() {
$(this).removeClass('priority-emergency').addClass('priority-low');
});
This is not the first version of the code - I already tried some other things, like:
$('div.priority#priority'+id).toggle(function() {
$(this).attr('class', 'priority-low');
}, function() {
$(this).attr('class', 'priority-medium');
}, function() {
...)
But this time it only toggles between the first one and the last one elements.
This is where my project is: strasbourgmeetings.org/todo
The thing is that your code will hook your handlers to the elements with those classes when your code runs. The same handlers remain attached when you change the classes on the elements.
You can use a single handler and then check which class the element has when the click occurs:
$('div#priority'+id).on('click', function() {
var $this = $(this);
if ($this.hasClass('priority')) {
$this.removeClass('priority').addClass('priority-low');
}
else if (this.hasClass('priority-low')) {
$this.removeClass('priority-low').addClass('priority-medium');
}
else /* ...and so on... */
});
You can also do it with a map:
var nextPriorities = {
"priority": "priority-low",
"priority-low": "priority-medium",
//...and so on...
"priority-emergency": "priority"
};
$('div#priority'+id).on('click', function() {
var $this = $(this),
match = /\bpriority(?:-\w+)?\b/.exec(this.className),
current = match && match[0],
next = nextPriorities[current];
if (current) {
$this.removeClass(current).addClass(next || 'priority');
}
});
[edit: working demo]
Assuming you have 'priority' as the default class already on the element at the initialization phase, this will cycle through the others:
$('div#priority' + id)
.data('classes.cycle', [
'priority',
'priority-low',
'priority-medium',
'priority-normal',
'priority-high',
'priority-emergency'
])
.data('classes.current', 0)
.on('click', function () {
var $this = $(this),
cycle = $this.data('classes.cycle'),
current = $this.data('classes.current');
$this
.removeClass(cycle[current % cycle.length])
.data('classes.current', ++current)
.addClass(cycle[current % cycle.length]);
});
I have tried myself to do this with the sole help of toggleClass() and didn't succeeded.
Try my method that declares an array with your five classes and toggles dynamically through
them.Do adapt to your own names.
//variable for the classes array
var classes=["one","two","three","four","five"];
//add a counter data to your divs to have a counter for the array
$('div#priority').data("counter",0);
$(document).on('click','div#priority',function(){
var $this=$(this);
//the current counter that is stored
var count=$this.data("counter");
//remove the previous class if is there
if(($this).hasClass(classes[count-1])){
$(this).removeClass(classes[count-1]));
}
//check if we've reached the end of the array so to restart from the first class.
//Note:remove the comment on return statement if you want to see the default class applied.
if(count===classes.length){
$this.data("counter",0);
//return;//with return the next line is out of reach so class[0] wont be added
}
$(this).addClass(classes[count++]);
//udpate the counter data
$this.data("counter",count);
});
//If you use toggleClass() instead of addClass() you will toggle off your other classes.Hope is a good answer.
I have a function which loops through rows in a table so that only one is shown at any given time.
I want to expand on this so that when I hover over the table, it shows all the rows, and then when I move away, it resumes showing one row at a time.
The Problem I have is that on hovering, the first function keeps going, is there a way to 'pause' the function. I've looked at various examples using ClearInterval(),but can't match them to my script.
//Calling The function that loops through the rows
function hideShow(time)
{
setInterval('showRows()',time);
};
//Set the time between each 'loop' and start looping
$(document).ready(function()
{
hideShow(2000);
}
);
//The hover function to show / hide all the rows
$(document).ready(function()
{
$('#dbTable1 tr').hover(function()
{
$('.Group td').removeClass('RoundBottom');
$('.Group').show();
},
function()
{
$('.Group td').addClass('RoundBottom');
$('.Group').hide();
}
);
}
);
Can anyone show me please how I can combine the two?
You need to keep track of the timer ID when you call setInterval:
var timerID;
function hideShow(time){
timerID = setInterval(showRows, time);
}
Then later on when you want to stop the repetition, call clearInterval and pass in that ID:
// ...
$('.Group td').removeClass('RoundBottom');
$('.Group').show();
clearInterval(timerID);
},
function()
{
hideShow(2000);
$('.Group td').addClass('RoundBottom');
// ...
You could just check the hovering state before doing anything else, like this:
function showRows() {
if (isHovering) {
return;
}
// ...
}
The isHovering variable is just a boolean with current hovering state, that could be set by your callback function.
With the above approach, you can set your timer only once and forget about it.
I'm using Drupal 7 and get my content with View module on page. And my pager Views Load More module. And my thumbnail effect hover, shadow etc. Image hover using this code:
var hoverImg = '<div class="hoverimg"></div>';
$(".thumb").each(function(){
$(this).children("div").each(function(){
$(this).find("a").append(hoverImg);
});
});
$(".thumb div").hover(function() {
$(this).find(".hoverimg").animate({ opacity: 'toggle' });
});
$(".thumb").hover(function() {
$(this).find("div").each(function(){
$(this).find(".shadow").fadeOut(500);
});
});
And getting number on my current thumbnail. This code:
var c = '';
var d = '';
$('.view-content div.views-row').each(function(){
c = 0;
d = 0;
var i = 1;
d = $(this).find('.thumbimg').length;
$(this).find('.thumbimg').each(function(){
sayi=i++;
$(this).append('<div class="img_no">0'+sayi+'</div>');
});
});
Everything is OK. All effects on start page. But when click Load More button, my effects can't work another page.
How do i solve this problem? Thanks.
The reason why it stops working is due to the hover function (and your other scripts/functions) only works on existing elements. So if you add something with ajax, it wont apply to that unless you reload the script after the ajax load.
Another option is to use live() or on() (for the hover part. On is the new version of live, added in jQuery 1.7).
Live and on listens for any existing or future elements.
A live script would look something like this:
$(".yourElement").live({
mouseenter:
function () {
// Do something
},
mouseleave:
function () {
// Do something
},
mousemove:
function () {
// Do something
}
});