I have a page which relies heavily on CSS3 animations. I am in the process of creating a script that will be the fallback that will work for those browsers that do not have CSS3 animations (looking at you IE...). I created the following script that will do the basic of what I need:
var $j = jQuery.noConflict();
$j(document).ready(function() {
//Hide All Elements to Fade Them In
$j(".frame-1, .frame-2, .frame-3, .frame-4, #tile-wrap, #copyright").addClass("hide", function() {
//Change Color of "Frames"
$j(".frame-1, .frame-2, .frame-3, .frame-4").addClass("color", function() {
//Frame 1
$j(".frame-1").fadeIn("slow", function() {
$j('.frame-1').delay(3000).fadeOut('slow', function() {
//Frame 2
$j(".frame-2").fadeIn("slow", function() {
$j('.frame-2').delay(3000).fadeOut('slow', function() {
//Frame 3
$j(".frame-3").fadeIn("slow", function() {
$j('.frame-3').delay(3000).fadeOut('slow', function() {
//Frame 4
$j(".frame-4").fadeIn("slow", function() {
$j('.frame-4').delay(3000).fadeOut('slow', function() {
//Tile
$j('#tile-wrap').fadeIn('slow');
});
});
});
});
});
});
});
});
});
});
});
The first part of the script works without issue (adding the class of .hide). But nothing after that fires or works. I am stuck because no errors are seen and I assume I have an error in my script.
Here is a fiddle of the script with the rest of the code.
Note: I am not very knowledgeable of writing JS and welcome any ways to improve the script, please provide examples.
FIDDLE NOTE Firebug shows a couple errors when running the fiddle. These errors are only on the Fiddle page and I believe are related to the jsFiddle not my code or page.
What I am attempting to Achieve
What I want is for each item (as listed by class or id) is to fade them in then fade them out after a delay then fade in the last div and it stays.
This will work, http://jsfiddle.net/VNfT2/2/. There is no callback for addclass. Having said that. AHHH!!!!!! This is NOT the right way to do it. Hint: When you see more than 10 }); in a row, stop and take a deep breath. :)
Edit: There are hundreds of plugins to do this (google for jquery slideshow). But, if you want to do it manually...look at this: fiddle: http://jsfiddle.net/VNfT2/5/
See http://jsfiddle.net/VNfT2/4/
var $j = jQuery.noConflict();
$j(document).ready(function() {
//Hide All Elements
$j(".frame-1, .frame-2, .frame-3, .frame-4, #tile-wrap, #copyright")
.addClass("hide")
//Change Color of "Frames"
.addClass("color");
//Frame 1
$j(".frame-1").fadeIn("slow", function() {
$j(this).delay(3000).fadeOut('slow', function() {
//Frame 2
$j(".frame-2").fadeIn("slow", function() {
$j(this).delay(3000).fadeOut('slow', function() {
//Frame 3
$j(".frame-3").fadeIn("slow", function() {
$j(this).delay(3000).fadeOut('slow', function() {
//Frame 4
$j(".frame-4").fadeIn("slow", function() {
$j(this).delay(3000).fadeOut('slow', function() {
//Tile
$j(this).fadeIn('slow');
});
});
});
});
});
});
});
});
});
As I said im my comment, you can call addClass with a string (the class) or with a function which return the class. But you can't do it with a string and a function... See api.jquery.com/addClass
And in your callback functions you should use $(this), it's faster because this way you don't search the element again.
The problem that your callbacks aren't called since they're supplied as the second argument.
addClass( className )
Description: Adds the specified class(es) to each of the set of matched elements.
.addClass( className )
.addClass( function(index, currentClass) )
Here are some tips:
1)
Try to only have 1 nested/callback function inside another function.
Refer to tip 4, then function fadeElementsInThenOut for an example.
2)
Don't repeat lookups.
Old code:
// Let's forget about the callbacks for now
$j(".frame-1, .frame-2, .frame-3, .frame-4, #tile-wrap, #copyright").addClass("hide");
$j(".frame-1, .frame-2, .frame-3, .frame-4").addClass("color");
New Code:
$j(".frame-1, .frame-2, .frame-3, .frame-4").addClass("color hide");
$j("#tile-wrap, #copyright").addClass("color");
3)
Use $(this) to reference the same element within a callback.
Old Code:
$j(".frame-4").fadeIn("slow", function () {
$j('.frame-4').delay(3000).fadeOut('slow', function () {
//...
});
});
New Code:
$j(".frame-4").fadeIn("slow", function () {
$j(this).delay(3000).fadeOut('slow', function () {
//...
});
});
4)
Don't use a callback if you don't have to.
Old Code:
$j(".frame-4").fadeIn("slow", function () {
$j(this).delay(3000).fadeOut('slow', function () {
//...
});
});
New Code:
$j(".frame-4").fadeIn("slow").delay(3000).fadeOut('slow', function () {
//...
});
Here's your code rewritten to fix the problems.
var $j = jQuery.noConflict();
$j(function () {
var frames = [ ".frame-4", ".frame-3", ".frame-2", ".frame-1" ];
var fadeElementsInThenOut = function( els, lastCallback ){
var el = els.pop();
if( el ){
$j(el).fadeIn("slow").delay(3000).fadeOut('slow', function(){
fadeElementsInThenOut( els, lastCallback );
});
}else{
lastCallback();
}
};
$j( frames.join( ", " ) ).addClass("color hide");
$j("#tile-wrap, #copyright").addClass("color");
fadeElementsInThenOut( frames, function(){
$j('#tile-wrap').fadeIn('slow');
});
});
Related
Scope of what I am trying to do: Various numbers of FAQ's are being pulled in upon build via yaml file which will have only the Question showing by default and then upon click the appropriate Answer will show.
I have figured out how to add a unique class for each question and each answer but I can't figure out how to toggle answer1 when question1 is clicked.
I appreciate any help! I am still learning javascript/jquery and get lost easily so if you could help explain or point to documentation of what I am missing I would appreciate it!
https://jsfiddle.net/texobyte/jns7v9ox/
$(".faqQuestion").each(function (i) {
$(this).addClass("question" + (i + 1));
});
$(".faqAnswer").each(function (i) {
$(this).addClass("answer" + (i + 1));
});
$("#toggle-faq h5").hide();
$("#toggle-faq").click(function () {
$("#toggle-faq h5").slideToggle("slow", function () {});
});
You could also try this (after changing the id "toggle-faq" to a class, as the other answer says):
$(".toggle-faq h5").hide();
$(".toggle-faq").on('click', function () {
if ($(this).hasClass("active")) {
$(this).children("h5").slideToggle();
$(this).removeClass("active");
return;
}
$(".active").children("h5").slideToggle();
$(".active").removeClass("active");
$(this).addClass("active");
$(this).children("h5").slideToggle();
});
The "this" means that it will only toggle the .toggle-faq that has been clicked on, and not all of them.
I have worked on you Fiddle and made few modifications to make it working. Here is the LINK
I have replace id="toggle-faq" with class="toggle-faq"; we should not repeat ids:
<div class="toggle-faq">
Also replaced this code:
$("#toggle-faq h5").hide();
$("#toggle-faq").click(function () {
$("#toggle-faq h5").slideToggle("slow", function () {});
});
With a better and working code:
// hide all answers at first
$( '.faqAnswer' ).hide();
$( '.toggle-faq' ).on('click', function () {
var $this = $(this);
// if this is already open
if ( $this.hasClass('active') ) {
return;
};
// close any other already open...
if ( !!currentSelected ) {
currentSelected.find( '.faqAnswer' ).slideToggle( 'slow' );
};
// ...and then open the clicked item
$this.find( '.faqAnswer' )
.slideToggle( 'slow', function () {
// now, make sure this is currentSelected
currentSelected = $this;
});
});
Let me know if you have any doubts. Good luck, have fun!
I inherited this modal/overlay/content close/empty method that works, but abruptly:
method.close = function () {
$modal.hide();
$overlay.hide();
$content.empty();
$(window).unbind('resize.modal');
};
To fade out gradually, I modified the method like below, but elements are left behind and subsequent clicks don't open new modals loaded with content, only the overlay:
method.close = function () {
$modal.fadeOut('slow', function() {
$(this).hide();
});
$overlay.fadeOut('slow', function() {
$(this).hide();
});
$content.fadeOut('slow', function() {
$(this).empty();
});
$(window).unbind('resize.modal');
};
What am I missing?
UPDATE: The solution is a single nested callback, based on garryp's answer, like this:
method.close = function() {
$overlay.fadeOut('slow', function() {
$overlay.hide();
$content.empty();
});
$modal.hide();
$(window).unbind('resize.modal');
};
Hide is asynchronous; the calls you have in your original code do not block while the transition occurs, execution moves immediately to the next. You need to use callbacks, like this:
var me = $(this); //Added to ensure correct this context
$modal.fadeOut('slow', function () {
me.hide(function () {
$overlay.fadeOut('slow', function () {
me.hide(function () {
$content.fadeOut('slow', function () {
me.empty();
});
});
});
});
});
Assuming the rest of your code is correct this should ensure the transitions fire one after the next.
Firstly, you do not need $(this).hide(). JQuery fadeOut automatically set display: none at the end of fading animation (read more: http://api.jquery.com/fadeout/).
That mean, in your case $content element will also have display: none after fadeOut animation. I expect you forgot to add $content.show() in modal open method.
I have created a very simple jQuery sliding function that works, but requires improvements. The basic timeline of the function needs to:
SlideDown on mouseenter
Stay visible until mouseleave
When mouseleaves, delay the SlideUp by 2 seconds
^^This works, but if you slide up and down several times, the function stops working for a few seconds. Can anyone please suggest a solution? JS FIDDLE attached
JSFIDDLE: http://jsfiddle.net/lord_dev/b1g50eqk/4/
$(document).ready(function(){
$hover = true;
$( "#slide" ).mouseenter(function() {
if($hover) {
$( ".slide--hidden" ).slideDown('fast');
}
});
$( "#slide" ).mouseleave(function() {
$hover = false;
$( ".slide--hidden" ).delay(2000).slideUp('fast').queue(function(){
enableHover();
$(this).dequeue();
});
});
function enableHover() {
$hover = true;
}
});
Replace your javascript with this. It works great if i understood your problem correctly.
$(document).ready(function(){
var thetimeout;
$('#slide').mouseover(function() {
clearTimeout(thetimeout);
$('.slide--hidden').slideDown();
});
$('#slide').mouseleave(function() {
thetimeout = setTimeout(function() {
$('.slide--hidden').slideUp();
}, 2000);
});
});
As it stands the remove function doesn't work. Any suggestions?
var toggle = new function() {
$(document).on('click', 'img', function () {
$(this).parent().toggle('slide');
})
}
var remove = new function() {
$(document).on('click', 'img',
setTimeout(function () {
$(this).parent().remove();
}, 1000);
)
}
The function your are looking for is .queue(). It will execute a provided callback after the previous animation has finished:
$(document).on('click', 'img', function() {
var $entry = $(this).parent();
$entry.toggle('slide').queue(function(next) {
$entry.remove();
next();
});
});
Working example: http://jsfiddle.net/rbBgS/
I am using on my site the plugin Quickflip with tabs on my site .
However if by exemple I click too fast on var2 and then var1 there is a bug.
That is why I am trying to put a timeout of 1s on each click of the tab so that it would wait for the flip to do.
Here is how I call the quickflip function (and tab)
$('document').ready(function () {
$('#flip-container').quickFlip();
$('#flip-navigation li a').each(function () {
$(this).click(function () {
$('#flip-navigation li').each(function () {
$(this).removeClass('selected');
});
$(this).parent().addClass('selected');
var flipid = $(this).attr('id').substr(4);
$('#flip-container').quickFlipper({}, flipid, 1);
return false;
});
});
});
Is there a solution to this please ?
I try to test your code and find out the problem that you mentioned.
[EDIT]
You want tabs can't be clicked until flip animation stop. I check the quickflip lib implementation and find out when div is flipping all the flip content display style will be set to "none". So I implement a "is animating" checking function.
Try this:
$('#flip-navigation li a').each(function () {
$(this).click(function () {
$('#flip-navigation li').each(function () {
$(this).removeClass('selected');
});
$(this).parent().addClass('selected');
var flipid = $(this).attr('id').substr(4);
var isAnimating = true;
$("#flip-container>div").each(function(index){
if($(this).css("display")!=="none"&&index<3){
isAnimating=false;
}
});
if(!isAnimating){
$('#flip-container').quickFlipper({}, flipid, 1);
}
return false;
});
});
[EDIT]
And this is the updated answer jsfiddle demo
Hope this is helpful for you.
There are few solutions that i know can solve your problem.
Have a look at Callback which is used to make another function wait to the other function to finish first before performing, and you can put it together with Unbind function or Event.Prevent
Code may look something like this:
$('document').ready(function () {
$('#flip-container').quickFlip();
$('#flip-navigation li a').each(function () {
$(this).click(function () {
$('#flip-navigation li').each(function () {
$(this).removeClass('selected');
$(this).$('#flip-navigation li a').unbind('click', handler); //Mod 1
});
$(this).parent().addClass('selected');
var flipid = $(this).attr('id').substr(4);
//Mod 2 ---- Start
$('#flip-container').quickFlipper({}, flipid, 1, function(){
$(this).$('#flip-navigation li a').bind('click', handler);
});
//Mod 2 ---- End
return false;
});
});
});
I am not entirely sure how to implement callback on the plugin, but here is a link to you that might be able to give you some idea how to implement callback on the quickflip plugin.