jQuery scrolling out of view issue - javascript

I am working on building a schedule. So far it's pretty straight-forward. There is one bit of functionality I am having issues with.
I have an ul that has a fixed height to allow scrolling. There are "Labels" (li.dayLabel) withing the ul that separate the hours. What I am trying to do is to have it so that when a label is scrolled out of view it will change the text in the placeholder to it's text. Then once that works, I need it to work in reverse. So when they label scrolls back into view it updates the placeholder. Basically, I am trying to make the placeholder be a title for the available items until another label is then scrolled out of view. This is for scrolling from the top. So as you scroll down the list the placeholder is meant to be a title for the section you are viewing until you reach another section and it takes its place. Then when you scroll back down I need it to replace the text with the previous li.dayLabel so the sections stay organized. I hope this makes sense.
You can see what I am trying to do by looking at the original that I am basing this off of. Notice how the placeholder changes as you scroll down the list and changes back when you scroll back up.
Demo: jsFiddle // Note: line 54 is the part that is in question
I originally used:
$(".snlf-schedule-list li.dayLabel:visible:first").text();
as the :first selector is suppose to only match a single element.
I later tried:
$(".snlf-schedule-list li.dayLabel:visible").filter(":eq(0)")
as this is suppose to be the same thing.
It seems that when an element is out of view it still is considered :visible I believe this is my issue.
Am I doing this completely wrong? I was under the impression that when you scroll an element like this it should no longer be :visible. After reading the documentation I have learned that this is not the correct selector to use.
It would appear that scrollTop is how I should be doing this. Now I have used scrollTop for scrolling down pages to disable animations when not in view but I am not clear on how to untilize this for a ul with scrollbars.
I tried:
var _first = $('li.dayLabel:first'); // next element to scroll out of view?
if( $(this).scrollTop() > (_first.offset().top+_first.height())) {
// Out of view
console.log("out");
} else {
// in view
console.log("in");
}
Updated Demo: jsFiddle
But it seems to be redundant as it's already calculating the first element so I am not sure how to get the correct element (the next one that's about to scroll out of view.) Then I need this to work when they scroll back up...
Any insight on this is much appreciated. Hopefully it's something simple I am just over complicating or missing completely.
Thanks,
Jeremy

The solution for my case was:
// Set placeholder text on scroll
var _scrollCagePositionTop = $(".snlf-schedule-list").offset().top;
var _first = $('li.dayLabel:first'); // first dayLabel element
$(".snlf-schedule-list").scroll(function(){
var _lastOffText = $(_first).text();
$("li.dayLabel").each(function() {
if ($(this).offset().top < _scrollCagePositionTop) {
_lastOffText = $(this).text();
}
});
$("#schedule-placeholder").text(_lastOffText);
});
What I did was set the known position of the top of the scroll cage (_scrollCagePositionTop)
When the user scrolls I set a variable _lastOffText that keeps track of the last item text content when scrolled out of view (less offset top than the palceholder). I then set this value to the placeholder.
This method allows me to have the proper text in my placeholder when the user scrolls up or down.
To fix the issue of an empty placeholder when the user scrolls back to the top I just set the default of _lastOffText to be the text of the first label ($(_first).text())
Hope others find this useful.
Here is the working demo: jsFiddle Final

Related

Angular js do not scroll when list element height change

I have a list of elements. Each element has an expanded and collapsed state.
When user expands one of the element, all other elements need to collapse. The list is inside a div which could be scrolled to allow seeing the entire list.
element 1
element 2
element 3
element 4
element 5
Lets say, element 1 is in expanded state. When I expand element 3, I collapse element 1. The problem is that when I do that, element 3 scrolls up. I want to avoid this and position element 3 to same position.
This is a pseudo code. There could be some minor syntax errors, but do ignore them, since my actual code has lot more going on and I don't want to paste the entire thing here.
The controller will include expand function like:
public expandElement(currentElement: any, previousElement: any) {
// get the height of previous element
var scrollOffset: number = angular.element("#" + this.getAnchorId(previousElement).offsetHeight;
// this function will collapse the element decreasing the height of it
previousElement.collapse();
// scroll to the newly expanded element
this.$timeout(() => {
var anchorId: string = this.getAnchorId(element);
var element = angular.element("#" + anchorId)[0];
var offset = element.getBoundingClientRect().top + scrollOffset;
this.$anchorScroll.yOffset = offset;
this.$location.hash(anchorId);
this.$anchorScroll();
});
previousElement = currentElement;
}
The html will look something like:
<div ng-repeat="element in listElements"
id="{{getAnchorId(element)}}">
<my-directive ng-click="expandElement(element, previousElement)"></my-directive>
</div>
This currently is not working at all, but even if I get it to work, there would be a small UI jump that could happen. I want to avoid scroll completely.
Is there another easy way to just block the scroll when angular expands an element?
Appreciate the help.
Thanks!
I got your problem, but i have one question. Consider you have more elements in the list and you will expand say 50th element then it has to scroll the main container to show the content of that expanded panel, i think it is the desired functionality in the scroll. I know i am not answering your question but, just thought of reconsidering it.
Probably you have to save scroll position and after click function got triggered change the scroll position back to saved state. There could be flick effect. If you want to hide the flick effect, hide the div show with a slow animation. Hope it helps.

Click function making page scroll in odd way (not to top of page)

First time asker, long time lurker.
I'm doing a fadein/out toggle that displays 1 of 2 charts depending on which button you click.
That bit works just fine, but I'm getting a weird page-jump glitch. Now, it's not the usual jump-to-the-top behaviour. I have that part covered in the code, and it doesn't do that.
Every time I click on one of the toggles, the page scrolls downward to the point where the chart area is at the bottom of the window.
But it gets weirder. If I make the browser window very short or very narrow (it's a responsive site), it stops doing this glitch. It's also not happening on iPhone or iPad at all, even though if I set the browser width to the same width as it would be on an iPad, the desktop browser still does the jumping.
There are no elements that are added/removed based on the viewport width in the area that's jumping around, and there are no anchor IDs that would be accidentally used as jump points.
Unfortunately I can't show the actual page to you, but I can show the script and a bit of the HTML.
The code for both toggles is the same, just with the IDs switched around.
The script:
$('#left-toggle > a').click(function(c)
{
c.preventDefault();
c.stopPropagation();
$('#right-toggle').removeClass('toggle-active');
$('#left-toggle').addClass('toggle-active');
$(pricing_subscriptionID).fadeOut('fast', function(){
$(pricing_singleID).fadeIn('fast', function(){
});
});
});
The HTML for the toggles:
<div id="chart-toggle">
<div id="left-toggle" class="toggle-active">Single Pricing</div>
<div id="right-toggle">Subscription Pricing</div>
</div>
"toggle-active" is just for styling.
Any ideas?
It seems to be almost wanting to centre the toggles on the page, but it's not quite putting them in the middle either.
JSFiddle: http://jsfiddle.net/TmrLw/
It's because of your link to #. Here are some ways you can fix this:
1. Replace "#" with something else
Instead of
Subscription Pricing
Try this:
Subscription Pricing
This will give you the cursor pointer you're looking for and avoid the page jump.
2. Create a class with the pointer effect
If you use this CSS rule:
.pointer {
cursor: pointer;
}
Then you can wrap your text with this class instead:
<div class="pointer">Subscription Pricing</div>
3. Remove the default effect of "#"
This Javascript will get rid of its default effect:
$('a[href="#"]').click(function(e)
{
// Cancel the default action
e.preventDefault();
});
Hope this helps
Probably its because the link's href is # which links to the top of the document.
try to remove the href attribute

Title text placement off after scroll

My problem is that after scrolling in the #leftnav the #leftnavHover does not position itself according to the new top css value. I need the #leftnavHover div to follow in the same way the native title text for the browser does.
Here's a fiddle http://jsfiddle.net/fauverism/b4rwb/6/
Here's a step by step of what I'm describing...
Visit the link and hover over Sabers in the nav
Scroll inside the nav div
Hover over Sabers again and you'll notice that the placement of the Sabers text inside of the #leftnavHover is in the same place. The div placement does not insert the new topAfterScroll array. The array is only present once and it then gets removed with the original value.
Here are some details...
I can't seem to store the array that is retrieved after the scroll from topAfterScroll into a new var
This only has to work in Chrome :)
Yes I know that this does seem strange to do since browsers handle this functionality just fine. It's a Chromium issue.
Just subtract the scrolled pixels using jQuerys scrollTop (API) on #leftnav like this:
$('#leftnavHover').text(this.title).css('top', this.offsetTop - $('#leftnav').scrollTop());
http://jsfiddle.net/b4rwb/7/

HTML fixed large element

I've been racking my brain and my Google Fu for a few hours now trying to find a solution to this one, but can't seem to come up with anything satisfactory.
I want to affix an element to the side of the page for some search criteria, much like Bootstrap's "Affix" plugin. (Demo Here). The problem is that it's going to be very common that the element is much taller than the window. So there will be scrolling of the element itself involved.
Usually this wouldn't be a problem because as the user hits the top + bottom of the document they would be able to see the top and bottom of the fixed element. (See bootstrap example while shrinking you're window very short). But we're planning on using infinite scroll on our results set, meaning there won't be a bottom to hit, and therefore they'll never see the bottom of the fixed element. As the user scrolls down, it needs to be bottom fixed so the user sees all criteria, then on the way up, it needs to be top fixed.
So I started off by modifying Bootstrap's plugin (I'm not actually using bootstrap). Now scrolling down the page is easy, using a fixed point on the bottom of the element means that it's not affixed until you reach the bottom of it.
But scrolling back up again is where I'm hitting issues.
Am I missing something really obvious and easy here (it is Monday morning after all), or does anyone know of a plugin / patch to bootstraps affix.
TL;DR
Need to affix a very tall element to the page and allow it to scroll. So it's fixed on the way down, then as they scroll back up, the element isn't fixed so it's also being scrolled up. Once the top of the element is hit, fix it there.
Is this what you Want to do DEMO
Simple jQuery function that will help.
$(function()
{
affix= $(".affix-top");
var affixHeight = parseInt(affix.height());
var affixTop = parseInt(affix.offset().top);
var affixBottom = parseInt(affixTop + affixHeight);
// Bind a scroll event for the whole page
$(document).bind("scroll", function(e)
{
// Calculate how far down the user has scrolled
var screenBottom = parseInt($(window).height() +$(window).scrollTop() );
// Test if the div has been revealed
if(screenBottom > affixBottom)
{
affix.attr("style","");
affix.css({"bottom":"0px","position":"fixed"});
}
else
{
affix.attr("style","");
affix.css({"top":"0px","position":"relative"});
}
});
});

How to make an element slide with the viewport as it scrolls?

I've Googled for this but must be using the wrong keywords.
Basically I want to use the effect that Magento and now Stack Overflow uses. That is, there is an element in a column, and when you scroll down, it sticks to the top of the viewport. And once scrolled up again, it goes back into the normal page flow.
This Ask A Question is a good page for example. Scroll down and watch the "How to Format" element come down (might need to make your viewport smaller if you have a large screen to see the effect).
I've noticed it is setting position: fixed in the CSS. The JavaScript however is obfuscated.
What's the easiest way to achieve this effect? Is there a jQuery plugin available?
Here is an article that should help: http://www.wduffy.co.uk/blog/keep-element-in-view-while-scrolling-using-jquery/comment-page-1/
I noticed google doing this in certain places, like here http://news.google.com/nwshp?hl=en (the left side navigation bar). From what I can tell, they checking the position on the page and then setting the item to a fixed position once the page is scrolled down enough for the element to start scrolling off the screen.
It looks like the other method, using jQuery to set the top margin will allow the element to lag behind and get choppy (if you don't use animation) since the javascript must continue to position the element.
Here is an example in Ext, it would probably help a lot if I didn't have the select in the event handler, but it works.
Ext.fly(document).on("scroll", function(e,t,o){
Ext.select(".pinnable").each(function(el,c,idx){
var y = window.scrollY;
if(!el.hasClass("pinned")){
var ypos = el.getY();
if(y>ypos){
el.addClass("pinned");
el.set({
originalY:ypos
});
}
} else {
var origy = el.getAttribute("originalY");
if(origy && y<origy){
el.removeClass("pinned")
}
}
});
});

Categories