.delay() a .css() action by multiplying an index number - javascript

I am trying to create a script that does the following:
Waits until a point on the page is reached by scrolling (.clients with an offset of 500px
Start fading in img's contained inside the .clients div once this event is triggered
Fade in with a slight delay between each item (so they fade in in sequence)
Due to other parts of my code the fade-in has to be with change of opacity:1 and cannot be .fadeIn()
I'm somewhere there but having a few issues. Here is my code:
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function(){
if ( $w.scrollTop() > targetOffset-500 ) {
$('.home .clients img').each(function(index){
console.log(index);
$(this).delay(500 * index).css('opacity','1');
});
}
});
First problem
The event does fire at the correct scroll-point in the page, but it continues to fire. I would like it to only fire once and then not register again. When 500 above .clients is reached, the event should fire, and never again.
Second problem
My .each() does not seem to work correctly. Everything fades in at once. My method for making a small .delay() between the fade-ins doesn't seem to be working. I tried multiplying the index by 500. So the first index is 0, so it fires immediately. The second index is 1 so it should fire after 500 milliseconds and so on. I'd like to work out why this method isn't working.
Any help appreciated. I'd appreciate trying to make the code above work rather than writing something entirely new, unless that's the only way. I'd appreciate explanation of what I was doing wrong so I can learn, instead of just pure-code answers.
JSFiddle

Sidney has attacked most of the problems except one. The scroll event fires multiple times, so it checks the conditional multiple times and then actually sets the animation multiple times. To keep this from happening, I typically like to add another boolean to check if the process has fired at all. I've simplified the code to make the changes more legible.
var working = false;
$(window).on('scroll', function(){
if($(window).scrollTop() > 1000 && !working){
working = true;
setTimeout(function(){
working = false;
}, 500);
};
});

As Tushar mentioned in the comments below your post, instead of using .delay() you could use a plain setTimeout().
On the jQuery docs for .delay() they mention that using setTimeout is actually better in some use-cases too - this is one of them.
The .delay() method is best for delaying between queued jQuery
effects. Because it is limited—it doesn't, for example, offer a way to
cancel the delay—.delay() is not a replacement for JavaScript's native
setTimeout function, which may be more appropriate for certain use
cases.
Using setTimeout your code would look like this:
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function() {
if ($w.scrollTop() > targetOffset - 500) {
$('.home .clients img').each(function(index) {
setTimeout(function() {
$(this).css('opacity','1');
}, (500 * index));
});
}
});
Also, you can unbind an event using .off()
so in your if ($w.scrollTop() > targetOffset - 500) { ... }
you could add a line that looks like this:
$(window).off('scroll');
Which would unbind the scroll handler from the window object.
You could also use .on() to reattach it again some time later. (with on() you can bind multiple events in one go, allowing you to write the same code for multiple handlers once.)

Please change your jquery code with following it will trigger event one time only and may be as per your reuirements :-
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function () {
if ($w.scrollTop() == 1300) {
console.log('here!');
$('.clients img').each(function (index) {
$(this).delay(5000 * index).css('opacity', '1');
});
}
});
Here i have take scroll hight to 1300 to show your opacity effect you can take it dynamically, if you want it 500 then please change the css as following also.
.scroll {
height:700px;
}

Related

jQuery animate running a lot of times

I'm having problems with my animate function. I want it to just run 1 time, but it doesn't. I've tried to debug it with using .stop(); but that didn't work either, so right now I have no idea how to solve this.
The JavaScript:
$(".box").hide();
$(".box").contents().not(".progress").hide();
$(".box").first().show(150, function showNext () {
var next = $(this).next(".box");
if (next.length > 0) {
next.show(150, showNext);
} else {
$(".box").contents().not(".progress").fadeIn(800, function () {
$(".progress").animate({
width: 'toggle'
}, 800);
});
}
});
The problem is easier to see at this jsfiddle:
http://jsfiddle.net/etBLj/
How do I solve this?
Thanks in advance!
The issue is that when you call $(".progress").animate(), the animation gets executed on every element with the "progress" class for the whole document. Since showNext() is called recursively, you end up with multiple animations for each matching element.
All you need to do is to restrict the call to animate to be applicable to the current element in your recursive loop. So change to $(this).next().animate and it will work.
Fiddle: http://jsfiddle.net/etBLj/1/
Additionally I think the JavaScript would become easier to understand if you separated the "showing of the headers" from the "animating of the progress bars", and replaced the recursive function with a simple each loop. For example: http://jsfiddle.net/etBLj/2/

Fade in or fade out based on scroll

$(document).scroll(function () {
var y = $(this).scrollTop();
if (y > 397) {
$('#aboutNav.fixed').fadeIn(500);
} else {
$('#aboutNav.fixed').hide();
}
});
As you can tell, this shows a fixed navigation. The CSS is fine, the positioning is great. However I want the navigation to become visible above 397px which it does fine.
However I want the navigation to fade in when I start scrolling:
.fadeIn(500);
When the user starts stops to look at content or whatever, I want the element to fade out
.delay(3000).fadeOut(350);
I believe this is something that can be done by doing an if statement within the first if statement. However a script to check if the user is scrolling and the working script above seem to collide.
Ideas, anyone?
If I understand you correctly. You want the nav to fade in if its above 397px and only when its scrolling... So this function will do that. If I misunderstood your question please clarify in the comments
$(window).scroll(function() {
clearTimeout($.data(this, 'scrollTimer'));//Lets the timer know were scrolling
//Hide/Show nav based on location
var y = $(this).scrollTop();
if (y > 397) {
$('#aboutNav.fixed').fadeIn(500);
} else {
$('#aboutNav.fixed').hide();
}
//TimeOut function that is only hit if we havent scrolled for 3 Seconds
//In here is where you fade out the nav
$.data(this, 'scrollTimer', setTimeout(function() {
$('#aboutNav.fixed').fadeOut();
console.log("Haven't scrolled in 3s!");
}, 3000));
});
JAN 23 UPDATE based on your comment
You can add this to you $(document).ready() function
$("#elementID").hover(function(){
//show here (mouse over)
$("#elementToShow").show();
},function(){
//Start timeout here, (mouse out)
setTimeout(function() {
$("#elementToHide").hide();
}, 3000);
}
Expanding on what Kierchon's answer a bit:
Since there's no real way to tell when the user is done scrolling (i.e. no event for 'finished scrolling') you'll have to use a event-delaying method called debouncing.
Debouncing is basically setting a timeout to run some code (a function) in the future, and if the event calling the debounced function get called again, you clear and reset the timeout, doing this repeatedly until the event finally stops being called. This method is to prevent events that fire repeatedly (such as scroll and resize) to only execute things after the final event fires and your delayed (debounced) code finally executes.
Here is a nice article on use of debouncing methods in JS.
As long as I understand what you need (which I think I do) - Here's a JSBin with some working code

jQuery wait longer until function is called

So I've got this element which I need to get the width() and height() of, but it keeps returning 0, but when i enter $('#lightingData').width() in the console, it gives me the right values. I think i need to use some other wrapper function, I have tried $(document).ready(function() {...}); and $(window).load(function(){...});
Are there other wrapper functions which will wait even longer before executing?
if the #lightningData element has display:none when the onload is triggered and your code executed, widht() and height() will return 0. You can explicitly call .show() on the element before checking for dimensions
$('#lightingData').show().width();
One of the things you can try is explicitly waiting for that particular element to be loaded before trying to call .width() and .height().
Try this:
$('#lightingData').load(function() {
...height and width manipulation here...
...don't forget about scope...
});
You should put this inside your $(document).ready(...), as you will want the document to at least know what $('#lightingData') is. Because you are getting 0 for the height and width and not errors, I can assume that they are at least found, before the methods are called.
UPDATE
Per the comments added by #Ian, I want to point out that this will only work for certain types of elements (URL, IFrames, Images/media, etc. - basically anything that needs to load its content). I am not going to update the code, since what I have above is correct if you are using it for one of these kinds of elements, and would be silly if you are using it for another. If you are using it for both, you need only add a condition/filter (based on your implementation) to determine if this code should be bound to that particular element.
If you are 100% sure that the width is still 0 at the point of $(document).ready()
try this:
$(function () {
$('#lightingData').show(function(e) {
var width = $(this).width();
//do something
});
});
Or, something stupid but will work for 90% of the case:
$(function() {
setInterval(function () {
var width = $('#lightingData').width();
//do something
}, 1000);
});
This one will delay the action for 1 sec after $(document).ready().
Without the exact scenario it's hard to give a specified solution.

Possible to have "mouseover for X seconds" functionality using jQuery?

I currently have several elements in a row that have a mouseover event that fires some animation. My problem is that if someone mouses over several of the elements in quick succession the animation gets a little frantic.
I'm curious if there is a way to have a mouseover event that only fires if the mouse is over an element for a certain amount of time (say 250 milliseconds). Can this be done with jQuery?
I would suggest you use setTimeout for this:
(function ($) {
var t;
$('ul li').hover(function() {
var that = this;
window.clearTimeout(t);
t = window.setTimeout(function () {
$(that).animate({opacity: .5}, 'slow').animate({opacity: 1});
}, 250);
});
}(jQuery));
If there are multiple items activated in rapid succession the timeout will override the timeout-id thus preventing the first item that should not start from animating.
It does not require any arcane plugin (although hoverIntent may provide some nice additional features you may want to use) and window.setTimeout is supported everywhere.
UPDATE
I updated the code sample to work.. was writing this from memory yesterday and didn't get the setTimeout call quite right.. Also see this jsFiddle for reference.
The issue I see with this is that it will execute the hover animation even if you leave the . So you could also add a $('ul').mouseleave(function() { window.clearTimeout(t) }); to prevent that.
greetings Daniel
I suggest that you check out the jQuery HoverIntent plugin ( 1.4k minified ). Here's the link: http://cherne.net/brian/resources/jquery.hoverIntent.html. It's a great plugin, I've used it many times!
Here's a small sampling of code:
var config = {
over: makeTall, // function = onMouseOver callback (REQUIRED)
timeout: 500, // number = milliseconds delay before onMouseOut
out: makeShort // function = onMouseOut callback (REQUIRED)
};
$("#demo3 li").hoverIntent( config )
yes:
to accomplish this put a setTimeout in your onMouseover function and a clearTimeout on mouseout
You may need a little more logic, but that's the nuts and bolts of it
here's an example of stop() in action, hope that will help:
without stop():
http://jsfiddle.net/5djzM/
with stop() cleaning the queue of animations:
http://jsfiddle.net/KjybD/

Javascript: do an action after user is done scrolling

I'm trying to figure out a way to do this. I have a list of boxes, each about 150px high. I am using javascript (and jquery) and want that, after a user scrolls down a page, the page will auto scroll so that the boxes line up with the rest of the page (that is to say, if the user scrolls and the y position of the page is not divisible by 150, it will scroll to that nearest point).
Now, I at the moment, I know I can activate an event using the .scroll() jquery event, and I can make it move to a certain point using .scrollTop(). But every pixel the user moves the scroll bar activates the whole function. So is there a way to delay the function from firing until the user hasn't scrolled, and if they should begin to scroll again, the function will halt?
As you are already using jQuery, have a look at Ben Alman's doTimeout plugin which already handles the debouncing of methods (which is what you are after).
Example shamelessly stolen from his website:
$(window).scroll(function(){
$.doTimeout( 'scroll', 250, function(){
// do something computationally expensive
});
});
This is basically the same as Šime Vidas' answer, but less complex:
var scrollTimeout = null;
$(window).scroll(function(){
if (scrollTimeout) clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(function(){yourFunctionGoesHere()},500);
});
500 is the delay. Should be ok for mouse scroll.
Sure, in the event handler for the scroll event, fire off a setTimeout for 100 or 200 milliseconds later. Have that setTimeout function you set inside of the scroll event handler do the positioning logic you mention above. Also have the scroll event handler clear any timeouts set by itself. This way, the last time the scroll event fires, the setTimeout function will get to complete as the scroll event has not cleared it.
The code:
var scrollTimeout = null;
var scrollendDelay = 500; // ms
$(window).scroll(function() {
if ( scrollTimeout === null ) {
scrollbeginHandler();
} else {
clearTimeout( scrollTimeout );
}
scrollTimeout = setTimeout( scrollendHandler, scrollendDelay );
});
function scrollbeginHandler() {
// this code executes on "scrollbegin"
document.body.style.backgroundColor = "yellow";
}
function scrollendHandler() {
// this code executes on "scrollend"
document.body.style.backgroundColor = "gray";
scrollTimeout = null;
}
This would be a scenario, where vanilla JavaScript would be useful.
var yourFunction = function(){
// do something computationally expensive
}
$(window).scroll(function(){
yfTime=setTimeout("yourFunction()",250);
});

Categories