Testing this out and I'm trying to figure out how to stop a delay if i click another attribute. I'll post the site address to make this explanation a lot better, but basically when you press menu my nav appears with a delay, when I press Assignment 6 I want everything else to hide, which it does, but I see that because I have a delay when it hides and it's not done delaying it will continue to print out the rest of the elements even though they are supposed to be hidden. Also a disclaimer, I've gotten a lot of heat on this site before because I think people think I expect an answer. This is not the case, I love to learn and although the answer would be helpful and I would be able to de-engineer it and learn it, I would much rather have some guidance. So yeah, I'm not just looking for an answer if anyone thinks that's what I'm on here for (I come on here when I can't figure it out any other way).
site
my jQuery script:
$(document).ready(function () {
//$('ul').hide();
$('ul li').hide();
$('nav>li').hide();
$('nav>h1>').click(function (event) {
event.preventDefault();
$('nav>ul li:hidden').each(function(i) {
$('nav>li').show();
$('nav>h1').hide();
$(this).delay(i*600).fadeIn(200);
});
$('nav>ul li:visible').each(function(i) {
$('nav>h1').hide();
$(this).delay(i*600).fadeOut(200);
});
return false;
}); //closes a.btnDown
$('nav>li').click(function (event) {
$('nav>h1').show();
$('nav>li').hide();
$('ul li').hide();
return false;
}); //closes a.btnDown
}); //closes .ready
setTimeout is a useful mechanism to solve what you are after. It waits for (at least) the delay specified, and executes the callback function.
var elements = $('nav>ul li:hidden');
var timeoutId;
function doAnimation(index) {
timeoutId = window.setTimeout(function () {
if (index < elements.length) {
$(elements[index]).fadeIn(200);
doAnimation(++index);
}
}, 600);
}
The clue is to declare the timeoutId outside a recursive function, and assign it within the function. By doing it in a recursive fashion, you don't start the next timeout before the current timeout is finished, and it can be aborted at any time.
window.clearTimeout(timeoutId);
I've made a little fiddle that demonstrates the concept, but I haven't implemented a complete solution. Hope this helps you get further with your project.
http://jsfiddle.net/pyMpj/
You can replace your delays with setTimeout and clear them with clearTimeout
$('nav>ul li:hidden').each(function(i) {
$('nav>li').show();
$('nav>h1').hide();
var fadeTimeout = setTimeout(function () {
$(this).fadeIn(200);
}, i * 600);
});
$('nav>li').click(function (event) {
$('nav>h1').show();
$('nav>li').hide();
$('ul li').hide();
clearTimeout(fadeTimeout);
return false;
});
Related
UPDATE: I reproduced the error in a plunkr: See http://plnkr.co/BpYfCNBESUT6ZkiSZHgx
The problem occurs when you do following:
Open website. Refresh website, while you see the page is loading in the browser tab, when you see the spinner in the tab.
Switch to another tab in your browser. If it doens't happen. Try again. If did as said, you are most likely seeing this:
You might say, this is not such a big deal, you have to be real fast to let this error happen. However, imagine somebody with a slow connection, he goes to another tab in his browser, continue watching his youtube video, while website is loading. When he comes back he just sees the page keeps loading.
Lets say ive this animation code:
$pageloaderbar.animate({
width: "46%"
}, {
duration: 700,
complete: function () {
$scope.continue();
}
});
When the first animation completes it calls an new function, called $scope.continue();. Which looks likes this:
$scope.continue = function () {
$timeout(function () {
$pageloaderbar.animate({
width: "100%"
}, {
duration: 500,
complete: function () {
$scope.PageIsLoading = false;
}
});
});
}
The problem is, when a user switches tab in his browser, between the $pageloaderbar.animate and the $scope.continue, the $plageloaderbar.animate function never reaches the complete function. The browser console shows the following error (Chrome)
My question is, how can i see if the user is active on the website? Or, how can i still execute the function, even if the user is not active on the browser tab?
Because there seems no one with an awnser, i have figured an little workaround myself. However, if someone still can explain why the animation breaks when switching tab, im very pleased.
The workaround was quite simple, i only had to add this code.
complete: function () {
if(document.hidden) {
$(window).on("blur focus", function () {
$scope.continue();
});
} else {
$scope.continue();
}
}
instead of:
complete: function () {
$scope.continue();
}
This is being caused by the jQuery animate function, which passes the animate options object to a function called speed. This function checks to see if the document is hidden - which it will be if the tab is inactive. If it is hidden, (or fx.off is set to true), all animation durations are set to 0.
You can see this on line 7137 in your plunkr's jQuery file.
if ( jQuery.fx.off || document.hidden ) {
opt.duration = 0;
As the animation now has no duration, it becomes synchronous, and so the fact that your complete function comes after the call to animate, is an issue.
To fix this, you would need to move the complete function declaration above your call to animate.
In the newer version of chrome this is related to visibility of the tab and your function is breaking due to that. you can use visibility API to know that tab is visible to the user or not.
Please have a look at this link which i found :
http://dystroy.org/demos/vis-en.html
$scope.continue = function () {
$timeout(function () {
$pageloaderbar.animate({
width: "100%"
}, {
duration: 500,
complete: function () {
$scope.PageIsLoading = false;
$("body").css("overflow", "auto");
$pageloaderwrap.addClass("page-loader-finished");
$scope.pageReady();
}
});
});
}
var $pageloaderwrap = $(".page-loader-wrap");
var $pageloader = $(".page-loader");
var $pageloaderbar = $(".page-loader .page-loader-bar");
$("body").css("overflow", "hidden");
$pageloaderbar.animate({
width: "46%"
}, {
duration: 700,
complete: function () {
if (document.hidden) {
$(window).on("blur focus", function () {
$scope.continue();
});
} else {
$scope.continue();
}
}
});
Try to define your continue function before call $pageloaderbar.animate . That may not be the main problem but, it is always possible to have a issue because of that.
Your solution is just a patch, not a real solution and not seems good. Even if it solves your problem, you must find a certain way to prevent this error.
I strongly recommend you to leave jquery. Such problems usually comes from jquery - angular incompatibilities.
Hey so I'm quite a noob but I was wondering if the script below didn't fire too much? And if so, can someone help me optimise it?
<script>
jQuery(function() {
jQuery(window).scroll(function() {
if((jQuery(".main-content").height() - jQuery(window).scrollTop()) < 702) {
jQuery("h1.product-single__title, .product-single__title.h1").addClass('titleScroll');
jQuery("#ProductPhotoImg").addClass('imgScroll');
jQuery("div#option_total").addClass('optionScroll');
jQuery(".template-product .product-form__item--submit, .template-product .product-form__item--quantity").addClass('addScroll');
}
else {
jQuery("h1.product-single__title, .product-single__title.h1").removeClass('titleScroll');
jQuery("#ProductPhotoImg").removeClass('imgScroll');
jQuery("div#option_total").removeClass('optionScroll');
jQuery(".template-product .product-form__item--submit, .template-product .product-form__item--quantity").removeClass('addScroll');
}
});
});
</script>
Thanks
From https://dannyvankooten.com/delay-scroll-handlers-javascript/
var timer;
$(window).scroll(function() {
if(timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(function() {
// actual callback
console.log( "Firing!" );
}, 100);
});
What you're looking for is called "throttling". By throttling a function, it only get's triggered x times per second, where you can define x. There are multiple ways of going about this and also a lot of libraries offer this functionality. You can find a nice read here on CSS-tricks which focusses on the lodash implementation.
Another great way to save performance is using requestAnimationFrame() (MDN). This way you don't have to listen to scroll events, but you can tell the browser to perform some script on the next repaint. You could use it like so:
function doThis(){
// javascript you'd like to trigger
window.requestAnimationFrame(doThis); // call again to create a 'loop'
}
window.requestAnimationFrame(doThis); // initial call to get the 'loop' started
What I basically want to achieve is create some kind of delayedChange plugin to be able to call some action (such as ajax call to the server) only after some delay the last input change event was fired. At the moment I've came up with this (jsfiddle). I should see alert only in 5 seconds (5000 msec) the last text change had place but it fires immediately.
(function ($) {
var timer;
$.fn.delayedChange = function (onchange, delay) {
return this.each(function () {
$(this).bind('change', function () {
if (typeof onchange == 'function') {
window.clearTimeout(timer);
timer = window.setTimeout(onchange.call(this), delay);
}
});
});
}
})(jQuery);
$(document).ready(function(){
$('input').delayedChange(function(){
alert($(this).attr('id'));
}, 5000);
});
The weirdest is that this code actually worked for some time, and then it's functionality just vanished for no reason. Obviously there is some explanation but I can't see it for now. Are there some more certain ways to implement/improve such plugin?
The functionality you've described is called "debouncing". Libraries such as underscore, lodash, and ampersand have a debounce method to make this effect convenient.'
With underscore, the code is:
$('input').each(function () {
$(this).on('change', _.debounce(...your function..., 5000));
});
No new function is needed, although you will need to include a new dependency.
I'd made a mistake with the first version. You need to generate a separate debounce function for each element, otherwise changing different elements will cause the timer to reset for all of the elements.
Firstly, apologies for the title, I could not think of a suitable one.
I am unsure as to why the hide() function within the below code comes back erroneous in firebug when triggered, I am pretty sure the rest of the code will work fine once I have ironed this flaw out, any help/suggestions would be appreciated.
Firebug Console error:
hide is not defined
it-services() it-services (line 396)
time = setTimeout("hide()",3000);
Code I have thus far:
var time;
$("#form").mouseenter(function() {
clearTimeout(time);
$(this).delay(800).animate({
right: 0
}, 2000);
}).mouseleave(function() {
function hide() {
$(this).delay(800).animate({
right: "-325px"
}, 1000);
}
time = setTimeout(hide,3000);
});
Thank you all very much for any help in advance,
Dan.
You're declaring the hide() function after you invoke it using setTimeout. Simply put the declaration before the setTimeout call.
Also, when you pass a string of code as first argument to setTimeout, it gets evaled. eval is evil. Just pass the function object:
function hide() {
$(this).delay(800).animate({
right: "-325px"
}, 1000);
}
time = setTimeout(hide, 3000);
There are 2 issues in the new code
Inside the hide function, the context of $(this) is not same as the
when it is being called inside the mouseout function.
Secondly, the hide function is defined as an anonymous function inside the mouseout function
I feel it would make more sense if it were a function declared outside the mouseover event handling function. That way you can globally reference it from the setTimeOut as well as the mouseout event handler. Try the below code. I believe this should solve the issue, or at least take you a step ahead.
var time;
var $form;
$("#form").mouseenter(function() {
$form = $(this);
clearTimeout(time);
$(this).delay(800).animate({
right: 0
}, 2000);
}).mouseleave(function() {
hide();
time = setTimeout(hide,1000);
});
function hide() {
$form.delay(800).animate({
right: "-325px"
}, 3000);
}
I need some help here..
Is it possible to cancel the chaining delay?
Mn.Base.TopBox.show = function(timedur){
$('#element').fadeIn().delay(timedur).fadeOut();
}
Mn.Base.TopBox.cancelFadeout = function(){
}
I read about queuing and tried some different approaches but I hadn't success...
$('#element').stop();
$('#element').queue('fx', []);
Thanks in advance,
Pedro
It isn't, .delay() doesn't play well with anything else since the timer keeps ticking and a .dequeue() is executed when it's up...regardless of if you cleared the queue and added a whole new one.
It's better to use setTimeout() directly if you intend to cancel, for example:
Mn.Base.TopBox.show = function(timedur){
$('#element').fadeIn(function() {
var elem = $(this);
$.data(this, 'timer', setTimeout(function() { elem.fadeOut(); }, timedur));
});
}
Mn.Base.TopBox.cancelFadeout = function(){
clearTimeout($('#element').stop().data('timer'));
}
What this does is set the timer and store it using $.data(), and when clering the animations, we're both calling .stop() to stop anything in process, and stopping that timer.
There's still the potential here for issues if you're firing this very rapidly, in which case you'd want to switch to storing an array of delays, and clear them all.