.offset().top returning the wrong value - javascript

I'm having a bizarre issue that I don't know how to solve and was wondering if you guys could help.
A bit of background: I have been asked to create a system where subpages of a page in wordpress are loaded on the end of that page in an infinite scroll. This is working correctly.
They also want the top nav links to load all content upto and including the page they clicked and then scroll to it.
If I scroll down (loading the pages) and then click a top nav link the scroll works correctly. However if I load NO further pages before clicking one of the links, the pages will load, and the scroll will start, but will only get some of the way before stopping. This is due to an incorrect value being given by offset().top. My question is why ?
function ajaxloadnscroll(index) {
//If the page has already been loaded then just scroll to it
if (pages[index].loaded) {
$('html, body').animate({
scrollTop: $("#" + pages[index].name).offset().top
}, 2000);
return;
}
//Loop through pages up to one clicked.
for (i = 0; i <= index; i++) {
current = i;
if (!pages[current].loaded) {
$.ajax({
url: pages[i].url,
async: false,
context: document.body,
success: function(data) {
if (data) {
$("#tempload").before(data);
pages[current].loaded = true;
if (current == index) {
$('html, body').animate({
scrollTop: $("#" + pages[current].name).offset().top
}, 2000);
}
}
}
});
}
}
//Increment current in order to load next page object on scroll.
current++;
return false;
}​
Any help you could give me on this issue would be really appreciated!

Related

Part of the page loaded with ajax. Problem with scroll position

I have a lot of problem with ajax on my web app.
Part of my website is loaded with the ajax method. Header and Footer loaded a static.
When I back to my previous page (button in browser) or refresh page (F5), my web application doesn't remember my scrolltop position (page height increases after loading) so almost every time it scrolls to the bottom of Footer.
I came up with a solution in javascript. My plugin saved a scrollTop position after click, and after loaded the page, it check it, if scrollTop is save:
$.plugin('scrollRestoration', {
init: function () {
var me = this;
me.registerEvents();
me.scrollRestorationLoad();
},
registerEvents: function () {
var me = this;
me._on(window, 'click', $.proxy(me.scrollRestorationSave, me));
},
scrollRestorationSave: function () {
sessionStorage.setItem('scrollPosition', $(window).scrollTop());
console.log(sessionStorage.getItem('scrollPosition'));
},
scrollRestorationLoad: function () {
if (sessionStorage.getItem('scrollPosition') != null) {
setTimeout(function () {
$(window).scrollTop(sessionStorage.getItem('scrollPosition'));
console.log(sessionStorage.getItem('scrollPosition'));
}, 2000);
}
else {
$(window).scrollTop(0);
console.log(sessionStorage.getItem('scrollPosition'));
}
},
});
but I'm not entirely happy with this solution, because it loads only after 2sec (after loading the ajax page)

Keep anchor tag href from jumping to it's page

I have the following anchor tag in my HTML that I use to load contents from that HTML location into a contents div on the current page. This anchor tag is part of Bootstrap treeview plugin I use for generating a table of contents:
1.1 Overview
In my JavaScript, I have the following code I use to listen for two events. One for the anchor tag so that I disable the default behavior and the other to process the anchor tag and load the contents and scroll to the anchor as follows:
$("a[href*='#']").click(function(e) {
e.preventDefault();
});
// Add smooth scrolling to all links inside a navbar
$treeview.on('nodeSelected', function (e, data) {
e.preventDefault();
if (data && data.href !== "") {
// Split location and hash
var hash = data.href.match(/[#].*/g)[0];
var location = data.href.match(/[^#]*/g)[0];
if (prevLocation === location) {
// Don't reload page if already at same location as last clicked
$('html, body').animate({
scrollTop: $(hash).offset().top - 55
}, 200);
} else {
prevLocation = location;
$('#contents').load(location, function () {
$('html, body').animate({
scrollTop: $(hash).offset().top - 55
}, 200);
});
}
}
$body.scrollspy('refresh');
$sideBar.affix('checkPosition');
});
What I am seeing is that the first time a click a node in my TOC, it loads the HTML into the contents div as expected but the second time I click it, it loads the HTML page that is referenced in the anchor tag despite my efforts to track if I previously loaded it as I do with the conditional logic above. I also notice that on the subsequent click, the anchor selector is not being called.
Any idea how I can accomplish having the TOC initially load the HTML from another page into the current page and then on subsequent calls just scroll to the anchor location (ie., chapter)?
Combining the two functions and returning false appears to work as follows:
$("a[href*='#']").click(function(e) {
e.preventDefault();
if (this && this.href !== "") {
// Split location and hash
var hash = this.href.match(/[#].*/g)[0];
var location = this.href.match(/[^#]*/g)[0];
if (prevLocation === location) {
// Don't reload page if already at same location as last clicked
$('html, body').animate({
scrollTop: $(hash).offset().top - 55
}, 200);
} else {
prevLocation = location;
$('#contents').load(location, function () {
$('html, body').animate({
scrollTop: $(hash).offset().top - 55
}, 200);
});
}
}
$body.scrollspy('refresh');
$sideBar.affix('checkPosition');
return false;
});

Scroll to the bottom of the page, reload it then repeat

I have checked all the possible questions that could be related to this but I cant seem to find anything that suits my case, either the answers were not good or incomplete.
In my case I have a html page with some php, displaying competition results. As the competition is live the page with results should scroll to the bottom of the page and then the page should refresh (so the possible new scores come in) and then repeat again and again. What would be the best solution for my problem?
The page size/length would increase as more data will come in the tables which are on results page.
Image:
EDIT:
This code now scrolls to the bottom of the page and then jump back to top and repeat and its exactly what I want, but I would like a page to refresh every time I hit the bottom and after this go to the top.
$(function() {
var pageScan = {
speed : 10000,
loop : true,
delayRestart : 1000,
start : function(){
pageHeight = $('body').height() - window.innerHeight;
pageScan.proc(pageHeight);
},
proc : function(to){
$("body").animate(
{scrollTop: to},
pageScan.speed,
"linear",
function(){
if (pageScan.loop) {
setTimeout(function() {
window.scrollTo(0, 0);
pageScan.start();
}, pageScan.delayRestart);
}
});
}
};
pageScan.start();
});
You can add some JavaScript to your page:
<script>
window.scrollTo(0,document.body.scrollHeight);
setTimeout(function (){location.reload()},5000);
</script>
This might be what you are looking for:
// Test data, ignore
for(i = 1; i < 21; i++) {
$('#results').append('<p>Test Result No.' + i + '</p>');
}
// Check every second (for example) if there is new data
// In this example there is always data
window.setInterval(function(){
update_results();
}, 1000);
// Check for new results
function update_results() {
$.ajax({
type: 'POST',
// Test data, ignore
data: {
html: 'new result'
},
// your ajax.php file
url: '/echo/html/',
success: function(data) {
// Append new results to $('#results');
// You might want to give back an array and loop through it with $.each(data, function() {});
// you might also want to check for "false" if there are no new results
$('#results').append('<p>' + data + '</p>');
// Scroll to bottom smoothly
$('html, body').animate({ scrollTop: $(document).height() }, 'slow');
}
});
}
jsfiddle
In your ajax.php-File you can echo the new scores:
echo json_encode($scores);
Given that $scores is an array of your scores which you probably have from your database.

AJAX load when reach bottom of container

I can't figure this problem out.
I use this JS call to load ajax content when I arrive at the bottom of the page:
$(window).scroll(function() {
if($(window).scrollTop() + window.innerHeight == $(document).height() ) {
and it works well, but now I want to change for loading the content when I reach the bottom of my container... I am trying this:
$(window).bind('scroll', function() {
if($(window).scrollTop() >= $('#postswrapper').offset().top + $('#postswrapper').outerHeight() - window.innerHeight) {
It loads the content when I reach the bottom of the container, but it loads it like 5 times... It's like as if it does a loop 5 times each time.
I want it to load ONCE, then when I go back DOWN the page and I reach the "NEW BOTTOM" of the container, load data 1 more time...etc
I tried many variables, but I can't figure it out. Any suggestions?
FULL AJAX CODE
$(window).bind('scroll', function() {
if($(window).scrollTop() >= $('#postswrapper').offset().top + $('#postswrapper').outerHeight() - window.innerHeight) {
$('div#loadmoreajaxloader').show();
$.ajax
({
url: "loadmore.php",
method: "get",
data: { page: pageNumber, perpage: perPage, search: "<?=$search?>", blogtag: "<?=$blogtag?>"},
success: function(html)
{
if(html)
{
$("#postswrapper").append(html);
$('div#loadmoreajaxloader').hide();
pageNumber++;
}
else
{
$('div#loadmoreajaxloader').html('<center>No more posts to show.</center>');
}
}
}); // close AJAX
} // close if()
}); // close $(window)
Scroll top is executed few times after you have the set true for the condition:
if($(window).scrollTop() >= $('#postswrapper').offset().top + $('#postswrapper').outerHeight() - window.innerHeight)
Here is a test fiddle for the window scroll, it always fires when you move the scroll and your condition does not limit the inner scope to execute only once.
test scrool event
Edit: simplest way is to use a lock while the ajax request is executing and while you are updating the UI with new content.
Why build something like this yourself when there are plenty of libraries out there? Just use an infinite scroll library that meets your needs. As you already use jQuery:
http://www.sitepoint.com/jquery-infinite-scrolling-demos/
But that's not the answer to your question. You should add a boolean to check if you're already loading new content. Let's say: loading. Initially set this boolean to false. If you request new data, set the boolean to true and in the check scroll statement add a check for this boolean. After adding the newly loaded content set the boolean to false again.
Fully working code:
var loading = false;
$(window).bind('scroll', function() {
if(!loading && $(window).scrollTop() >= ($('#postswrapper').offset().top + $('#postswrapper').outerHeight() - window.innerHeight)) {
loading = true;
$('div#loadmoreajaxloader').show();
$.ajax({
url: "loadmore.php",
method: "get",
data: {
page: pageNumber,
perpage: perPage,
search: "<?=$search?>",
blogtag: "<?=$blogtag?>"
},
success: function(html) {
if(html) {
$("#postswrapper").append(html);
$('div#loadmoreajaxloader').hide();
pageNumber++;
loading = false;
} else {
$('div#loadmoreajaxloader').html('<center>No more posts to show.</center>');
}
}
}); // close AJAX
} // close if()
}); // close $(window)

Section will be overlapped by header when come from another page

I have the following problem. What I want is when the user clicks in the navigation bar on "Contact" it will link to the contact page. This is a single page. When you are on contact and then clicking at the bottom of the page on, for example "Over ons" it should be redirect to the homepage (single page) and stop at that section. This works, but when you come from another page, the current section is overlapped by the header.
The jQuery code will not use the offset of the header, only when you are navigation inside the index.html.
Is there a way to fix the issue, so the section will not be overlapped by the header?
Live example:
http://codepen.io/anon/pen/NqxxQd
jQuery code:
// An offset to push the content down from the top
var offset = $('#header').outerHeight();
$('#primary-navwrapper li:not(.prev-page, .next-page), .list-of-links li').find('a[href^="#"]').click(function(event) {
event.preventDefault();
$('#primary-navwrapper li a').removeClass("current");
$(this).addClass("current");
var anchorId = $(this).attr("href");
var target = $(anchorId).offset().top - offset;
$('html, body').animate({ scrollTop: target }, 500, function () {
window.location.hash = anchorId;
});
});
function setActiveListElements(event){
// Get the offset of the window from the top of page
var windowPos = $(window).scrollTop();
$('#primary-navwrapper li a[href^="#"]').each(function() {
var anchorId = $(this);
var target = $(anchorId.attr("href"));
var offsetTop = target.position().top - offset;
if (target.length > 0) {
if (target.position().top - offset <= windowPos && (target.position().top + target.height() + offset ) > windowPos) {
$('#primary-navwrapper li a').removeClass("current");
anchorId.addClass("current");
}
}
});
}
$(window).scroll(function() {
setActiveListElements();
//updateLocationHash();
});
Your code to scroll down to each section needs to be placed in it's own function called something sensible like FireActiveElement. Give it one parameter that sends through your anchorId string. Your click listener then needs to call that function.
So you have a function similar to:
function FireActiveElement(anchorId) {
var target = $(anchorId).offset().top - offset;
$('html, body').animate({
scrollTop: target
}, 500, function () {
window.location.hash = anchorId;
});
}
Then, what you can do is something like this:
function CheckHash() {
if (window.location.hash) {
FireActiveElement(window.location.hash);
}
}
Then you'll need to add that function as a callback to your body fade in:
$('body').fadeIn(500, CheckHash);
Difficult to test this works myself, but hope that helps you.
P.S.
If you need to have more things that are fired upon page load, you might want to change the fadeIn slightly to something like:
$('body').fadeIn(500, function() {
CheckHash();
// Examples:
SomeOtherFunction();
FireMeOnPageLoad();
});

Categories