EDIT: This software package is the full and undoctored version of what I'm trying to fix here. The problem is in the /data/renderpage.js script. Feel free to examine this before continuing.
https://github.com/Tricorne-Games/HyperBook
I really appreciate all the help guys!
=
I am polishing a jQuery script to do the following in a rigid sequence...
Fade out the text.
Shrink the size of the container div.
Preload the remote HTML ///without showing it yet!///
Open the size of the container div.
Fade in the new remote HTML.
I do not mind if steps 1 and 2, 4 and 5 are combined to be one whole step (fade/resize at the same time). It's when the new HTML is loaded it interrupts the entire animation, even from the beginning.
The idea is that I do not want my remote HTML to show until after the animation renders right. I want the original text to fade out and the container div close up, then, behind the scenes, ready the text of the new HTML, and then have the container div open up and fade the new text in.
It seems when I call the load(url) function, it instantaneously loads the page up, and the animations are still running (like the new HTML ends up fading out, only to fade back in, and not the original text out and then the new one in). Either that, or the whole function is calling each line at the same time, and it's disrupting the page-changing effect I want.
Here's my current script setup...
$(document).ready(function() {
// Start-Up Page Load (Cover, ToC, etc.)
$('#content').load('pages/page1.htm');
// Navigating Pages
$(document).on('click', 'a', function(e) {
e.preventDefault();
var ahref = $(this).attr('href');
$('#content_container').animate({height: 'hide'}, 500);
$('#content').fadeTo('slow', 0.25);
$('#content').load(ahref);
$('#content').css({opacity: 0.0});
$('#content').fadeTo('slow', 1.0);
$('#content_container').animate({height: 'show'}, 500);
return false;
});
});
What is it wrong I'm doing here? I have used the delay() function on every one of those steps and it doesn't solve the problem of holding back the new text.
jQuery objects can provide a promise for their animation queues by calling .promise on the jQuery element.
You can wait on one or more of these to complete using $.when() and then perform other operations.
The following does a fade out and slide up in parallel with the load, then (only when the animations complete), slides it down then fades it in (in sequence):
$(document).on('click', 'a', function (e) {
e.preventDefault();
var ahref = $(this).attr('href')
var $container = $('#content_container');
var $content = $('#content');
// Slide up and fadeout at the same time
$container.animate({
height: 'hide'
}, 500);
$content.fadeOut();
// Load the content while fading out
$('#content').load(ahref, function () {
// Wait for the fade and slide to complete
$.when($container.promise(), $content.promise()).then(function () {
// Slide down and fadein (in sequence)
$container.animate({
height: 'show'
}, 500, function () {
$content.fadeTo('slow', 1.0);
});
});
});
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/pffm1tnb/3/
The only issue with this version is that the load may complete faster than the fadeout/slideup and show the new data too early. In this case you want to not use load, but use get (so you have control over when to insert the new content):
// Load the content while fading out
$.get(ahref, function (data) {
// Wait for the fade and slide to complete
$.when($container.promise(), $content.promise()).then(function () {
$content.html(data);
// Slide down and fadein (in sequence)
$container.animate({
height: 'show'
}, 500, function () {
$content.fadeTo('slow', 1.0);
});
});
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/pffm1tnb/4/
Notes:
return false from a click handler does the same as e.stopPropagation() and e.preventDefault(), so you usually only need one or the other.
I started with the JSFiddle from #Pete as no other sample was handy. Thanks Pete.
Update:
Based on the full code now posted, you are returning full pages (including header and body tags). If you change your code to .load(ahref + " #content" ) it will extract only the part you want. This conflicts with the second (better) example I provided which would need the pages returned to be partial pages (or extract the required part only).
Additional Update:
As $.get also returns a jQuery promise, you can simplify it further to:
$.when($.get(ahref), $container.promise(), $content.promise()).then(function (data) {
$content.html(data);
// Slide down and fadein (in sequence)
$container.animate({
height: 'show'
}, 500, function () {
$content.fadeTo('slow', 1.0);
});
});
The resolve values from each promise passed to $.when are passed to the then in order, so the first parameter passed will be the data from the $.get promise.
JSFiddle: http://jsfiddle.net/TrueBlueAussie/pffm1tnb/11/
The issue is because you're not waiting for the hide animations to finish before loading the content, or waiting for the content to load before starting the show animations. You need to use the callback parameters of the relevant methods. Try this:
$(document).on('click', 'a', function(e) {
e.preventDefault();
var ahref = $(this).attr('href'),
$content = $('#content'),
$contentContainer = $('#content_container');
$contentContainer.animate({ height: 'hide'}, 500);
$content.fadeTo('slow', 0.25, function() {
// animation completed, load content:
$content.load(ahref, function() {
// load completed, show content:
$content.css({ opacity: 0.0 }).fadeTo('slow', 1.0);
$contentContainer.animate({ height: 'show' }, 500);
});
});
});
Note that for the effect to work the most effectively on the UI you would need to perform the load() after the animation which takes the longest to complete has finished.
Instead of using the load() function, you can use the get() function and its callback paramater to save the HTML into a variable before actually putting it into the element with html().
After doing all the animations to fade out and close the old box (and maybe inside an animation-finished callback function) you'll want to use something like the following:
$.get(ahref, function(data) {
// JQuery animation before we want to see the text.
$('#content').html(data); // actually inserts HTML into element.
// JQuery animation to fade the text in.
});
Using a bunch of the code everyone posted here, I rewrote the segment I originally had to follow suit. This is now my working result.
$(document).ready(function() {
// Start-Up Page Load (Cover, ToC, etc.)
$('#content').load('pages/page1.htm');
// Navigating Pages
$(document).on('click', 'a', function(e) {
e.preventDefault();
var ahref = $(this).attr('href');
$('#content').fadeTo('slow', 0.0)
$('#content_container').animate({height: 'hide'}, 500, function(){
$('#content').load(ahref + '#content', function(){
$('#content_container').animate({height: 'show'}, 500, function(){
$('#content').fadeTo('slow', 1.0);
});
});
});
return false;
});
});
You can use deferred or callbacks function
$(document).on('click', 'a', function(e) {
e.preventDefault();
var ahref = $(this).attr('href');
var dfd1 = $.Deferred();
var dfd2 = $.Deferred();
var dfd3 = $.Deferred();
var dfd4 = $.Deferred();
$('#content_container').animate({height: 'hide'}, 500, function(){
dfd1.resolve();
});
dfd1.done(function() {
$('#content').fadeTo('slow', 0.25, function() {
dfd2.resolve();
});
});
dfd2.done(function() {
$('#content').load(ahref, function() {
$('#content').css({opacity: 0.0});
dfd3.resolve();
});
});
dfd3.done(function() {
$('#content').fadeTo('slow', 1.0, function() {
dfd4.resolve();
});
});
dfd4.done(function() {
$('#content_container').animate({height: 'show'}, 500);
});
return false;
});
Related
I've tried to create a jQuery effect using fancy box to contain my content and within that is a large image with thumbnails below. What I was trying to make happen was when the thumbnails are clicked then the large image updates (see RACE Twelve image as an example). This works fine but the problem is when I go to another fancy box on my website (SEE RACE ONE box) then that image has been updated to be whatever thumbnail was clicked last.
I thought this might be event bubbling but preventing default hasn't helped.
I'm very new to jQuery and know that this is something stupid that I'm doing.
Any advice would be greatly appreciated? Thank you :)
Live version of page: http://www.goodwood.co.uk/members-meeting/the-races.aspx
jsfiddle for jQuery: http://jsfiddle.net/greenhulk01/JXqzL/
(function ($) {
$(document).ready(function () {
$('.races-thumbnail').live("click", function (e) {
$('.races-main-image').hide();
$('.races-image-wrap').css('background-image', "url('http://www.goodwood.co.uk/siteelements/images/structural/loaders/ajax-loader.gif')");
var i = $('<img />').attr('src', this.href).load(function () {
$('.races-main-image').attr('src', i.attr('src'));
$('.races-image-wrap').css('background-image', 'none');
$('.races-main-image').fadeIn();
});
return false;
e.preventDefault();
});
$(".races-image-wrap img").toggle(function () { //fired the first time
$(".races-pop-info").show();
$(this).animate({
width: "259px",
height: "349px"
});
}, function () { // fired the second time
$(".races-pop-info").hide();
$('.races-main-image').animate({
width: "720px",
height: "970px"
});
});
$('#fancybox-overlay, #fancybox-close').live("click", function () {
$(".races-pop-info").show();
$(".races-main-image").animate({
width: "259px",
height: "349px"
});
});
});
})(jQuery);
$('.races-main-image') will select all elements with that class, even the ones which aren't currently visible.
You can select the closest '.races-main-image' to the clicked element as per the code below (when placed inside the click event handler)
$('.races-main-image', $(e.target).closest('.races-fancy-box'))
So your new code should look like:
$('.races-thumbnail').live("click", function (e) {
var racesmainimage = $('.races-main-image', $(e.target).closest('.races-fancy-box'));
var racesimagewrap = $('.races-image-wrap', $(e.target).closest('.races-fancy-box'));
racesmainimage.hide();
racesimagewrap.css('background-image', "url('http://www.goodwood.co.uk/siteelements/images/structural/loaders/ajax-loader.gif')");
var i = $('<img />').attr('src', this.href).load(function () {
racesmainimage.attr('src', i.attr('src'));
racesimagewrap.css('background-image', 'none');
racesmainimage.fadeIn();
});
return false;
});
I've also removed your 'e.preventDefault();' return false; includes that, and was preventing e.preventDefault() from being executed in any case.
I'm using jQuery Mobile, I have a bunch of javascript code that is executed like this
$(document).on("pageshow", function () {
$(function () {
var $container;
$container = $(".items-section");
return $container.imagesLoaded(function () {
$container.masonry({
itemSelector: "article.hlisting"
});
return $container.masonry({
isFitWidth: true
});
});
});
});
But since I'm retrieving objects via ajax and redrawing them on screen, some of the same code needs to be also executed inside of a $(document).on("scrollstop", function()
My question is. How can I refactor the code in order to be called on two cases?
If it's exactly the same code that you want to be called then just pass multiple, space separated events as the first argument:
$(document).on("pageshow scrollstop", function() {
// your code here
});
I'm facing a problem in jquery :animated selector, i use the callback function inside the jquery animate function to call ajax page after animation done but the problem : the calling page via ajax is called double times !
$('#elemId').click(function(){
$('html,body').animate({scrollTop: $('#sections_display').offset().top-100}, 500, function(){
$('#sections_display').load('page.php');
});
});
The result "page.php is loaded twice times ! in firebug".
So i tried:
$('#elemId').click(function(){
$('html,body').animate({scrollTop: $('#sections_display').offset().top-100}, 500);
});
if ($('html,body').is(":animated")) {
$('#sections_display').load('page.php');
}
The problem is if ($('html,body').is(":animated")) always return true during animation of the page but i want to return true after animation finished.
Also i tried :
$('#elemId').click(function(){
$('html,body').animate({scrollTop: $('#sections_display').offset().top-100}, 500, function(){
if ($(this).is(":animated")) {
$('#sections_display').load('page.php');
}
});
});
The result "page.php is loaded twice times".
The result "page.php is loaded twice times ! in firebug".
That's because you're attaching the event to both html and body. Try just html:
$('#elemId').click(function(){
$('html').animate({scrollTop: $('#sections_display').offset().top-100}, 500, function(){
$('#sections_display').load('page.php');
});
});
I want to show an image after there is hover on link for atleast 1500ms or there is a click. How can I implement this minimal period hover condition while showing up the image ?
The image should remain visible until there is hover on the link or on itself. & should disappear as the mouse moves out of both. How can I implement this ? Thanks in advance!
http://jsfiddle.net/sSBxv/
$('a').click(function() {
alert(1); // alert on click
})
.hover(function() { // when mouse is entering
var $this = $(this);
// set timeout, save timeout id on element to clear later
$this.data('timeout', setTimeout(function() {
$this.click(); // click after 1500ms
}, 1500));
}, function() { // when mouse is leaving
clearTimeout($(this).data('timeout')); // stop the timeout
});
Try this
var hoverTimer;
$("linkSelector").hover(function() {
hoverTimer = setTimeout(function() {
$("imgSelector").show();
}, 1500);
}, function(){
clearTimeout(hoverTimer);
}).click(function(){
clearTimeout(hoverTimer);
$("imgSelector").show();
});
Something to the effect of...
$("#MyLinkSelectorId").hover(function() {
//Do anything you need to do here when it is clicked/hovered
setTimeout(function() {
//Do all of the other things here
}, 1500);
});
Switch out hover with click or bind multiple events to take care of both event types. To hide the images, you can either use a selector on the images with the .hide() method or you can set the opacity if the browser supports it.
$("a.class").hover( function (){ //First parameter is onmouseenter, show the image
$("img").show();
}, function (){ //second is onmouseleave, set a timeout that will hide the image
setTimeout( function(){
$("img").hide();
}, 1500);
}).click( function() { //on click, hide the image right away.
$("img").hide();
});
Since it looks like you haven't already tried something I'll give you the simplest way using jQuery (please note I haven't tested this):
$("#idOfDiv").mouseover(function() {
setTimeout("alertMsg()",1500);
});
function alertMsg()
{
alert('Ive been entered for 1500ms')
}
Also if you're serious about software development you should've been able to come up with this yourself.
I'm pretty new to jQuery (and javascript for that matter), so this is probably just something stupid I'm doing, but it's really annoying me!
All I'm trying to do is add a speed to jQuery's hide and show functions. The code I'm using is:
for (var i in clouds) {
$(clouds[i]).click(function() {
$(this).hide();
});
}
to hide clouds when they're clicked on, and
function fadeLogo(state) {
var element=document.getElementById('logo');
if (state=='home') {
element.hide;
element.src='images/home.png';
element.show;
}
else {
element.hide;
element.src='images/webNameLogo.png';
element.show;
}
}
to hide an image, change it and then show it again. This is called by
onMouseOver=fadeLogo('home') onMouseOut=fadeLogo('logo')
This works fine, but happens instantaneously. Whenever I try to include a speed, either as 'slow', 'fast' or in milliseconds, it won't work, they just stay in their original states. Even adding hide() without a speed throws up an error in Safari's error console:
TypeError: Result of expression 'element.hide' [undefined] is not a function.
No errors are reported for the clouds, they just sit there not doing anything!
Hope someone can help!
Thanks
EDIT:
Now have this for the image change:
$(function() { //This function fades the logo to the home button on mouseover
$('.logo').hover(function() {
$(this).fadeOut(
'slow',
function () {
$(this).attr ('src','images/home.png').fadeIn('slow');
});
}, function() {
$(this).fadeOut(
'slow',
function () {
$(this).attr('src','images/webNameLogo.png').fadeIn('slow');
});
});
});
Which fades the image out and in no problem, but doesn't change between the 2 images...
Oops, should have been #logo. Got that one working now, onto the pesky clouds...
The hide() method is used like so:
for (var i in clouds) {
$(clouds[i]).click(function() {
$(this).hide( 'slow' ); // or you can pass the milliseconds
});
}
As for the image hiding you should do something like this:
$( 'selector for your image' ).hide (
'slow',
function () {
$( this ).attr ( 'src', 'images/other.png' ).show ( 'slow' );
}
);