JavaScript setTimeout causes a scrollTop Event? - javascript

I have a collection of divs in a document that can be filtered by classname, as in hiding and showing elements. The list can be filtered by clicking either a corresponding element in the list or one of the items in the top menu.
I made this pen to illustrate my problem.
I call the filter function for each click event, which hide all elements, and after using window.setTimeout() I display the right ones like below. This is to get a delay as well as to trigger fade-in css3-animations.
var filter = function(el){
if(filterClass==='all'){
window.setTimeout(function(){
$('.project').show(); //show all projects
$('#filter-all').addClass('active');
}, 100);
}
else{
window.setTimeout(function(){
$('.'+filterClass).show(); //show filtered projects
$('#back2').show();
$('#'+elClassName).addClass('active');
}, 100);
}
};
The problem is that when I use window.setTimeout() the view scrolls up to the top, even if the view is in the bottom of the page.
Try this in the pen:
Show all
Scroll down to the bottom so that the top of the document is not visible in the view.
Filter by clicking some div.
Result:
It gets filtered correctly, but the view always scrolls/jumps up to the top.
Why is this happening?
I expected it to stay in the same relative scroll view when possible and otherwise end up at the bottom of the scrollbar. This is to me the standard and desired behavior.

The page scrolls top because you hide elements. So there is no more downward scrollable area. If you had 1000 items and you filtered 999 and show only 1, then what would you expect? The scrollable area would be way too short.
For your case, I would remove
$(".project").hide()
And hide non-matching items only:
else{
window.setTimeout(function(){
$('.'+filterClass).show();
$(".project:not(" + '.' + filterClass + ')').hide();
$('#back2').show();
$('#'+elClassName).addClass('active');
}, 100);
}
Not a perfect solution because there would be some scroll top. But in most cases, it would be less.

Related

scroll to top of newly generated div

So in my site, when a button is clicked,I dynamically generate a div, which contains a grid of images. It goes like this:
$('.prod-images').click(function(){
var prodImages = generateProdImagesGrid(this);
$('#prod-images-grid').html(prodImages).show();
});
This works fine. And I have another button which will close this div on click.
Now this div can be taller than the screen and require vertical scrolling. The problem is that because of all the CSS/styles in this page, this div always opens only at the scroll position where it was closed. So when I open it first time, it is scrolled to the top and everything is fine. Now, suppose I scroll this div halfway down and then close it. Next time when it is opened, it opens at that scroll position.
I tried doing:
$('#prod-images-grid').html(prodImages).scrollTop(0).show();
This does not work (at least in chrome) because the div is not fully rendered when the scrollTop() call is executed.
The only way I can make this work is to give a long delay between the div rendering and the scrollTop call like so:
$('#prod-images-grid').html(prodImages).show();
window.setTimeout(function(){
$('#prod-images-grid').scrollTop(0);
},10000); //call scrollTop after 10 seconds
As you can imagine, this is not at all a good solution. Does anyone have any suggestions on how I can render the div so that when its visible, it is scroll to its top position?
Doing:
$('#prod-images-grid').html(prodImages).scrollTop(0).show();
means that it's the <div id="prod-images-grid"> which gets scrolled; since this div has no content, it cannot be scrolled.
Rather do:
$(document).scrollTop(0);
$('#prod-images-grid').html(prodImages).show();
The 0 argument of scrollTop can of course be modified to point to the position of the document where you want your dynamically generated div to show.
You can handle a function after the contents is showing whith this propety of .show():
$( ".target" ).show(interval, handler);
Like this:
$('#prod-images-grid').html(prodImages).show(1, function() {
$('#prod-images-grid').scrollTop(0);
});
(you can change 1 for any other value)

Get fixed position based on underlying div if still exists

I created a rough idea of the filter I'm creating offline.
Basically the filter or "update row" section shows red, blue or green if available. Can be any combination of results(ie. just blue and green) I have a div that's positioned at the top at all times. So when viewing the blue section it is over that row(fixed to top).
If I select the filter the positioning is lost as you can imagine as sometimes rows will not be present from above or the underlying row may not exist anymore. My question is. How can I get the row name underneath at click then use that to scroll to once everything else is complete. Of course if it's not present then just go to top of table_listing.
success: function(data, textStatus, XMLHttpRequest) {
jQuery('#table_listing').hide().html(data).fadeIn('slow'); // put our list of links into it
$('html, body').animate({
scrollTop: $("#table_listing").offset().top
}, 1000);
I created a working example HERE.
So the idea is to use $(document).scrollTop() to find how much the page is scrolled. Then compare it with the height of the divs to find the one we are on. Then we store it in a variable in a dynamic manner. When user clicks filter button, we know where we have been before, so we can scroll back to that element. Check out the console to see the result. Since scroll() event is only bind to user manual scrolling, it will not be affected by animating of scroll, as you want to have.

Increase top position of element on scroll until height is reached (jQuery)

I have two containers set up on a page, the first and second. The second is after the first container.
I'm trying to write a jQuery function that upon reaching the end of the first container, on scroll, it changes the top position of the second container (negative top position) so it feels as if the second container is being scrolled up and over the first container.
I have the following so far, which is doing a few things to get me started. Firstly, on scroll, I know when I reach the bottom of the first container and when the trigger should happen to begin scrolling the second container up. But then, I am not very sure how to get the top position to negatively increment as I scroll.
Any help?
function caseStudyScroll() {
var secondContainerHeight = $('.second-container').height();
$(window).scroll(function() {
if ($(document).height() - secondContainerHeight <= ($(window).height() + $(window).scrollTop())) {
var windowScroll = $(window).scrollTop();
} else {
}
});
}
caseStudyScroll();
Rather than using jQuery to handle the scrolling, you could use CSS transitions when you hit the trigger. When you hit the trigger, add a class/id that changes its top position by whatever amount puts it where you need. In the id/class of the second container, put the following:
-webkit-transition: top 1s;
transition: top 1s;
This will move the container to the new position in one second.
Hope that helps!
EDIT: Now that I think about it, I may have misunderstood your question. Do you want this to happen constantly, while scrolling up? That is, you want your second container to stay on the page while you scroll past the first one? In that case, changing the position to fixed in a similar method should work.

jQuery .scrollTop() not scrolling to li elements as expected

I essentially have an unordered list of list items in a div that doesn't scroll to the next element properly. I'm just trying to have a button to scroll up and down the list.
While the code does scroll, it doesn't match up with the li elements. After every click, it scrolls up a little bit, then down on the next click. I've tried walking the DOM and verifying the element it is scrolling to is an li element, but didn't see the issue.
I have the following jsfiddle:
http://jsfiddle.net/YD9s5/9/
The elements are:
A scrolling div with an id of photos-div
An unordered list with an id of photos-li (whoops, leaving it for now)
List items with incrementing ids of photo-li-X where X is a number
The code being used to scroll the div is:
$('#photos-div').scrollTop($('#photo-li-' + i).offset().top);
The i variable is being incremented, as you can see.
The problem is that .offset() gets the position of an element relative to the entire document, and that position is constantly moving up. So once you've scrolled to item 1, it returns the .offset().top that item 1 currently has in the document, which is now where item 0 used to be.
Add console.log( $('#photo-li-0').offset() ); to the top of your scrollToElement() function and you'll see what I mean. Notice that the top offset keeps decreasing, quickly moving into the negative numbers as it moves off the top of the document.
The fix is to take the difference between the offset of $('#photo-li-'+i) and $('#photo-li-0') (or the container $('#photos-li') itself) and scroll to that instead:
var newpos = $('#photo-li-' + i).offset().top - $('#photo-li-0').offset().top;
$('#photos-div').scrollTop(newpos);
http://jsfiddle.net/mblase75/x4hQP/ (incorporates other improvements)
It appears that .offset() only measures from the top of the document. You are interested in how far the element is from the top of #photos-div. Here's a working version where I track the position in the div manually. Notice in the console that when I log the value of .offset() it's relative to the document rather than the scrolling div.
Seems that there should be a way to do this without carrying the position of that div in state. Working on it...
Here's my more programatic solution.

How to know when a user scrolls past a <div>?

I'm building something where I show users items that they haven't seen.
Each item is in a <div>, so when the user scrolls past a div, or views the div, I want that item to be marked as having been seen.
Google reader does this, if you scroll past an item in your feed there it automatically marks it as read.
How can this be tracked? Advice please.
Note: It shouldn't be restricted to using the mouse to scroll, hitting page down/up, using arrow keys, etc should also be counted. The main criteria is that the user has seen a div.
You need jQuery's scrollTop.
Something like:
$(window).scrollTop() > $('#mydiv').offset().top;
for when it first comes into view, or add $('#mydiv').height() to the top offset if you want it to be marked when it's fully in view.
You could use a solution like this, http://www.appelsiini.net/projects/viewport, which I used in the past.
Or see this for other solutions: Detecting divs as rendered in the window to implement Google-Reader-like auto-mark-as-read?
Have a look at $("#divid").scrollTop().
I think you'll need something like this...
$(window).scroll(function(){
var scroll = $(this).scrollTop();
var vieweditems = $('div').filter(function(){
return scroll> $(this).offset().top;
//compare the div's offset top with the window scroll position
// this returns the collection of viewed divs
})// this object is colleection of viewd divs
.removeClass('hilight')
//Remove the class which distinguishes the unread and read items
.map(function(){
return this.id.split('_')[1];
}).get();
//This is the collection of ids of viewd divs
//vieweditems now holds the ids of viewed divs
});

Categories

Resources