I am loading results in with ajax with an infinite scroll, however, when you click an item in the list and navigate away from the page, then click the back button, you are back at the top of the list.
I can't figure out how to make the user return to the position they left off.
See the site I am working on:
https://www.studenthouses.com/search/manchester/
Scroll down a few times, then click a property, then click back and you will see what I mean.
I can't remember the result position and load them in because it would take too long, so really I need the browser to remember the DOM when it comes back to the page, or cache it some how.
Is there a solution to this?
Many thanks
Sure there is and it's a piece of cake. Well, it's a cookie, actually :)
You don't need much to solve this problem.
First, get some cookie here: Cookie API
Second, you'll have to encode the data in the cookie somehow. If you have multiple pages like that one, you'll have to separate them somehow or use a key-value pair and store something like this:
manchester=3522
Whenever you enter the page, load the cookie, wait the page to be fully unrolled (you use AJAX or similar, you'll have to wait for the page being unrolled, window.onload won't do).
If there is no cookie, skip this step:
scroll the page down to the offset you have loaded from the cookie: scrollTo
Next, whenever the page is scrolled, modify the cookie. To avoid thrashing you'll want to do this in a polling manner. Use setInterval() at maybe 500 milliseconds and check if the user changed the scrolling position. If he did, save the cookie with the new value.
Related
I am making a browser game in html, css, and javascript, written in perl. Health and stamina are kept in the server and I use javascript to show the user a live updated count of these stats while the current page is loaded. This works fine, however if the user switches tabs or switches away from the browser and leaves it running in the background, the count value you see when you return does not keep up properly. So when you switch back to the browser, your counter might say 50/100 stamina when you actually have 100/100. So when you do something in the game (loads a new page) the server updates the counter to the true amount because the javascript is just keeping time to show the user a "live" rolling view in the browser.
Is there a way to ensure the javascript counter will continue to function even if the page/tab isn't active or on the forefront? Aside from completely re-writing my game to include continuous live server pushes in what is displayed on the browser to the user?
Say you are playing the game. You see your health and stamina regenerating. You switch to another program for a minute, then return to the game in the browser. You notice your health and stamina have not updated while you were away. But when you perform an action in the game, this value is updated to what it should be because it is tracked internally on the server. This is what I would like to fix. Hope that makes sense!
I have not tried anything to fix this issue yet besides searching the web and ending up on this site without a really "good" answer in sight, so I decided to ask the question.
Continuous server pushes wouldn't work either. Anything in the main event loop like a timer, or events happening when it's out of focus, gets slowed down by the browser to conserve resources. Some mobile browsers will stop it together.
The answer to the question is to change how your app keeps track of these stats.
Now some will say to use WebWorkers to run the timer in a separate thread but this won't solve all your issues. You'd still have a different version of the issue, like if someone restored your webpage from sleep or something along those lines. No background task can survive that.
You mention that you track these stats also on the server. That's convenient, so the most obvious thing you should do is detect when the tab comes back into focus using the Window focus event. You would then make all the calls to the server to fetch the most up-to-date stats and reset the timers based on that fresh data. To stop it from showing stale data while the request is in flight, you might choose to show a loading spinner or something during that period.
Another common way of fixing this is you keep around on each timer increment a var which says when the data last came back (a timestamp). When you leave focus, you detect this with the blur event and store that last timestamp somewhere. Then they come back into focus, you handle the focus event and calculate the difference between the current time and the last recorded time before defocus (blur). You may be able to recalculate from this period what the values should be.
But if your server has this info, it'd be far less error-prone and easy to just ask the server when they refocus.
I want to implement a functionality wherein on clicking the back button, i come back to the same position. A good example may be http://www.jabong.com/men/clothing/mens-t-shirts/ . Here, if you scroll down and hit on a product, and click back from the product page, you reach the same position of the page where that product is.
The example shown here doesn't append anything in the url to remember the position. Also, it doesn't use pushstate or history.js (not loading through ajax).
Any insights into how I can do this?
EDIT: Im using infinite scrolling pagination (like pinterest), and the pages keep loading on scrolling down. When I go back, the query runs again and reloads the page. If I was on the 4th page before, after going back, the pages don't load until page 4 and so there's a break, thus I cant reach that position.
So my question is how do I do this with infinite scrolling?
You can use history.replaceState to store the scroll position just before the page is left. When the user comes back you can check if there is some scroll position present in history.state, and if, scroll to that position.
One more thing to consider is that browers can as well persist the page when leaving (if cache policy allows them) and restore it when returning, including scroll position. In that case no browser events will be fired when coming back, besides the pageshow event (check browser support) which will tell you via event.persisted whether the page is served from cache or not. You maybe want to listen to that event to clear the scroll position from the stored state, again via history.replaceState.
Finally, you want to consider that browsers do scroll restoration on their own and you probably need to disable it via history.scrollRestoration (but check browsers support)
If you can use JQuery in your application. You can try WayPoint Plugin its very simple to use and from your question, I think that is what your looking for.
here is an example Infinite Scrolling and of how it functions:
http://imakewebthings.com/jquery-waypoints/shortcuts/infinite-scroll/
Also take a look at these tutorials for infinite scrolling using various other plugins, you can use which ever one suits your needs the best.
http://www.jquery4u.com/tutorials/jquery-infinite-scrolling-demos/
EDIT:
If your looking to restore the location where the user left off with infinite scroll using the back button, this is a little bit more tricky and requires some more work on your part and how your data is being generated. Please take a look at a similar question here:
Is it possible to write an "Infinite Scroll" javascript that can handle the back button?
I got the same problem and the situation was pretty similar: no bookmark or parameters changed on the url.
Here is my solution and it works:
1) You can use window.history.go(-1) or window.history.back(), which is the same as back button on the browser, to navigate to previous page.
2) When you use this function, for some reason it might not be back to the position on your last page (eg. you select a picture on the bottom of page and it redirects to next page. When you click 'back' button, it goes back to the top of the previous page). In this case, you need to set the current scrollY value var currentScrollYonSession = window.scrollY on the session or other place, depending on your code, when the app redirects to the next page (normally it's onClick() or onChange() event). When you click the 'back' button and the app loads the previous page, firstly check the session that the scrollY value is null or not. If it's null, just load the page as it is; otherwise, retrieve the scrollY value, load the page and set the scrollY value to the current page: window.scroll(0, currentScrollYonSession).
I came up with a solution for my app to achieve this:
$(document).on('click', 'a', function() {
var scrollpos = $(window).scrollTop();
localStorage.setItem('scrollpos', scrollpos);
});
This uses LocalStorage to save how many pixels we are down from the top of the page.
var scrollplan = function() {
var foo = true
if ((foo == true) && $('.box').length > 30) {
var bar = localStorage.getItem('scrollpos')
$("html, body").animate({ scrollTop: bar}, 500);
}
$('.photosbtn').on('click', function(){
var foo = false
});
};
The initial page load has 30 photos with class boxes. My pagination begins by clicking a btn with class photosbtn.
I implemented infinite scroll like so:
new_page_value = 1;
$(window).scroll(function() {
if($(window).scrollTop() >= $(document).height() - $(window).height() - 200) {
new_page_value = parseInt(new_page_value) + 1;
get_page(new_page_value);
}
});
When the user almost reaches the bottom of the page (200px left) the function get_page() is called. This contains an ajax call that gets all the contents of the new page and appends it to the <body> of the document.
Now I just realized if my site gets big and instead of having 10 small pages I have a gazillion giant pages then the user's browser might crash if they are persistent enough to keep infinite scrolling for long time.
Would this be a possible solution to this problem:
I will keep appending the new pages to the document <body> until the 10th page, after that I will be replacing the <body> content entirely instead of appending. So using html() rather than append().
I just don't know if this will actually work to prevent crashes. Will .html() clear the "memory" of prior html that was brought in via ajax?
I really think this is a common issue for many sites with AJAX list content. So let's take an example at some of the most popular ( think of scale = experience ) websites and their solutions :
Google Images
If you check out images.google.com and you search for whatever, for e.g. "guiness", you will see a page full of results (actually the images are ajax loaded, not the html-code, so the page is with fixed height) and when you scroll at the bottom there is a button "Show more results". This might be solution one of your problem, but is it really necessary to place a button at the bottom after, for e.g. the 10-th page? I really think it is generally a good solution for page usability and memory leaks, but it is really not a necessary option as we can see in :
Facebook
Facebook Newsfeed is another story. There is a button "Show more posts", but I really don't know when exactly it is displayed rather than loading the next page of posts. It happened to me once to load 10-15 pages of posts, only by scrolling. And you know Facebook posts include videos, photos, AJAX comments and a lot of more Javascript fancy stuff, which take a lot of memory. I think they've managed to do this after a lot of research, how much of the users scroll to the bottom.
Youtube
Youtube has "Load more videos" at every page, so the solution is basically similar to Google, except that Google renders the whole html of the page and on scrolling just loads the images.
Twitter
Twitter supports infinite scrolling. Yep, they do it may be because tweet is 140 characters and they don't need to worry about memory so much. After all who is willing to read more than 1000 pages of tweets at one page load. So they don't have a button for "load more" and they don't need one.
So there are two solutions :
Use infinite scrolling ( you should consider how much content you load and how rich it is )
Use button : "Load More"
Most of all, you should not delete already loaded content of a list.
Nowadays everything is Javascript and Javascript has garbage collection, so it is very hard to unload the DOM ( if it has Javascript, not plain text ) and manage to remove the Garbage from Javascript. Which means that you won't free the whole allocated memory of the unloaded content from the browser.
Also think about of your requests, why would you need to load again something, that you have already loaded at first place. It costs another server request, meaning another database request and so on.
I have worked with this before and here are some of my thoughts:
a) If you are appending data to the memory page(s) at a time then it is not an issue, some browsers might not respond well but most of the lastest browsers will render without any problem so long as there is enough memory on the target machine, you could probably see how the ram usage increases as you append pages. Use chrome for this as each page is a separate process and it has an inbuilt task manager
b) regarding usage of html(), it indeed removes the markup but it does so at a heavy cost as it tries to take care of special conditions and has an overhead and accesses all the controls nested within the container that you are replacing (not sure about the last pat), but it has a cost. A simpler way to clear the DOM would be to use the innerHTML property and set it to empty, jquery does this but it is at a later point in the html() api. open up the api and look at the method.
using innerHTML
$("<selector>")[0].innerHTML=""
Also deletion of pages sounds weird to me as a user, what if I want to go back to the initial comments and please dont think about making it an infinite scroller too.. I have tried and given up after the number of bugs raised but we had a genuine use case for it and I had to stick a button up there, but this wasnt when the user scrolled away from the first page, this is when the user landed on a 3rd page but now needs to see the results above it.
Hope that answers your question and btw infinte scrolling is your friend use it, dont over engineer a case which will probably only be tested by your QA team. Its better to spend your effort somewhere else.
Yes it will, if i may suggest an idea after let's say 5 pages just delete the first page and append the new one instead of deleted all of the previous pages. good luck :)
Google does this thing where on search results after you've visited a search result page and don't find what you and and click "back" to the Google Results there's then a "Hide results from xxxxxxxxxxx.com".
This doesn't happen till you're back on Google's page because I can see the effect. How is this done? Is it a onFocus on the window with a record of you having clicked that search result or something?
I guess they simply just track how much time you spent on the result website and if you didn't spend much time there, they will assume you didn't find what you want? So in overly simplistic way:
When you click a search result, save a timestamp and the target website url in a cookie. This can be done by a simple onclick handler, it fires before you are taken to the new site.
You click back and the time is checked against the clicked time and the url is added to remove results from xxxxx.com if the time spent is < y seconds.
Then again I am just guessing and as I cannot get this functionality to work for me, I cannot find out to be even remotely sure. But If I ever had to implement something like this, this would be something I would explore first.
Notice the search URL: it's http://www.google.com/#sclie.... The page doesn't actually reload, the results are loaded with Ajax. When you press Back, however, it does reload, or rather, onload and related events are raised again.
Is there a way to push pages on change rather than putting a timer on a web page to refresh every x mins? I guess what Im trying to do is not refresh an entire page when only a portion of it may have changed. I have seen on FB when an update happens, it has message saying new content available.
Perhaps you could MD5 a page then when an update happens the MD5 changes and the page could be checking this. Not exactly push but it would reduce the traffic of an entire page.
How can I update a webpage when a change occurs on the server?
a good practice to "reduce the traffic" is to load content through AJAX requests.
the "timer" you mentioned above is my preferred method with my previous comment and a bit of extra logic. This is know as long-polling.
One way is to watch for specific keyboard events and/or mouse events and update the page if certain criteria is met within those events.