Browser cache and history back button (hashing, history.js) - javascript

I have problem with browser back button. Problem exists for IE and google chrome.
I'm creating autoload mechanism for search engine. Mechanism works like google search.
Procedure of building:
1) typing keywords
2) ajax search request
3) response as json
4) building results list using json
5) append list to container
If i have builded results and redirect to another page and back to the page with results, results desapear. I tried a lot solutions described by developers like hashing, history.js and many more but every one is not working.

When you go back, the original HTML of the page is loaded from the cache. Everything you added through Javascript is not stored, so you will have to restore that modification on page load.
For that you can use the popstate event. When that even is fired, you'll need to restore the information. You can do that by re-executing the AJAX request and process the result. Therefore you must save enough information in the url (or hash) to be able to execute the same request again.
That also means, you may need to do earlier requests! For example, if you execute an ajax request to get item X of a list, where X increments each time after the request (so you can get the next item on each click), you will need to make sure that you load all items again. If you don't do that, you will only get the original items on the cached page, and the latest item that was AJAXed, while the items inbetween will be missing.
But if you use pushState or replaceState to store states, you can also store additional data. You can use this to store the JSON result with the state, so you don't need an additional request. Anyway, this is an optimization and is not strictly needed, so you should start with implementing the AJAX request being fired on popstate. You'll need that anyway, because the data may not always be stored with the state, so you will always need the AJAX request as a fallback.

Related

Is there a way to send POST data to another form and return the result of that form?

I need to send form data to another page that will allow the user to do something in a form and return the result of that form back to the original page? Is this possible? I know it's not ideal, but the issue is that I need to make a "drop-in" solution that does not need to be integrated with other code. I know it's a very specific request and scenario.
I know how to send POST data that doesn't require any user input on the processing page. i.e. I can send POST data to 'calculate.php' which will do the math and send it back, but if I need additional user input on 'calculate.php', how can I still send it back?
An example of expected results would be:
Page #1: User enters a number and presses submit to go to next page.
Page #2: User enters a second number and presses submit to finish.
Back to Page #1: User receives sum of both numbers.
Obviously, this is a really redundant thing to do, but I'm trying to simplify the problem as much as possible.
EDIT: There a few restrictions I forgot to add.
Page #1 is not my application, I am developing Page #2 as a "drop-in" solution for Page #1. Essentially, I can only use Page #1 to call Page #2 and receive a response from it. The problem is that I need to be able to allow for user input on Page #2.
I know I can post to Page #2 and then post to Page #1 again, but what if I need to maintain the state of Page #1. For example, if there's an open Web Socket connection.
Please note, I understand that this may be impossible or extremely difficult, but if I don't ask I'll never know right?
You want it with PHP or any other language. If you are running Php on server side then you can use Global variables like $_GET and $_POST.
Page #1: Use Post/Get method to send data to second page.
Page #2: Receive all fields' values using Globe variables ($_GET and $_POST). You can use these values as default values of form fields. Now submit this data to page 1 using post or get method.
Back to Page #1: Here you will receive the data of first page from second page and newly posted data from page 2
Either of these should work:
Never leave the page - use AJAX / XMLHttpRequest to call out to other pages to process chunks of data
Do everything on page 1 using "postbacks" -- the form targets are the same page, there is a state variable like "stage=1", and you use JavaScript to add set hidden variables for any additional state that's needed.
... PHP state validation and processing for the different stages ...
... one or more blocks of HTML for the page (PHP if / else can be used to choose between multiple page views) ...
Edit for added restrictions:
Have page 2 use postbacks or AJAX to collect the additional information
I figured out a few ways to do it.
Update a Database (or Data Store of some sort, depends on security needs) and have Page #1 listen for events from a separate page (on the same server as the database). Very similar to the way PayPal's Instant Payment Notification (IPN) works. I was actually able to set up server sent events with it as well.
Essentially, Page #1 sends data to Page #2 where the user will perform the function and then Page #2 will send POST data to a listener somewhere (either on the same server or Page #1's server), the listener will update a database and Page #1 will be listening or pulling to an event handler that will send an update once the database updates.
Use JavaScript Child/Parent Window functions. This is okay if Page #1 and Page #2 are on the same server, but can get messy and browsers have a lot of restrictions and it varies depending on browser.
Page #1 will open Page #2 in a child window, after the user performs a function, Page #2 will call a function that accepts the result data on Page #1.

How to perform an ajax call on page unload?

I have a dashboard where users can toggle some input values in order to configure the appearance of the page.
I want to store those changes in a DB table, so when user comes back, the dashboard appears according to the specific user configuration retrieved from the DB.
I know how to send those values to DB and how to retrieve them
I don't want to make ajax calls every time the user changes a configuration.
Instead, I think this senario would be better:
Page load (retrieve DB configuration if exist)
User toggles the configuration ui items (e.g. checkboxes, select etc) and the appropriate client side changes take place (some divs get hidden, some others are shown etc and the config input values are stored to a hidden field), but no ajax call takes place.
When user clicks a link to another page, the configuration input values (which have been stored to the hidden field) are sent to the DB via ajax call.
MY QUESTION
One solution(?) would be the use of onbeforeunload event like this:
window.onbeforeunload = function(e) {
// Perform the ajax call
return 'Do you want to save the configuration changes?';
};
But, if the user's browser prevent popups, the function will not get executed?
Is there a way to perform an ajax call on onbeforeunload event, without calling a dialog box?
No. During unload, the browser will kill all pending requests. So the AJAX might or might not arrive at the server. You also can't do it inside the handler of the beforeunload event because the first A in AJAX means: Asynchronous -> Just put the request on the stack and eventually execute it. So the request will be looked at only after the handler returns. But very soon after that, the browser will kill anything related to the page.
The solution is to always send updates to the server while the users makes changes. Put those into a special "temporary" table from which you can restore the state later.
You could also use something like localStorage in the browser but then, the data wouldn't move with the user. For example if they were working on an tablet and that broke or had a power loss, they could move to their PC to continue where they left off.
You can't guarantee that an Ajax call will complete in this way, see Aaron's response. My suggestion would be to use something like localStorage to read / write the user's settings instead.
If you need a user's appearance to persist across multiple devices, add a periodic request to read / write the recent updates from localStorage to the central DB.
Try using Navigator.sendBeacon on the visibilitychange event.
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "hidden") {
navigator.sendBeacon("/ajaxUrl");
}
});
Regarding Navigator.sendBeacon(), MDN details that when leaving a page,
the browser may choose not to send asynchronous XMLHttpRequest requests.
With the sendBeacon() method, the data is transmitted asynchronously when the user agent has an opportunity to do so, without delaying unload or the next navigation. This means:
The data is sent reliably
Regarding the visibilitychange event, MDN recommends:
Web sites often want to send analytics or diagnostics to the server when the user has finished with the page. The most reliable way to do this is to send the data on the visibilitychange event

How to refresh screen data in JavaScript without making the page slow?

I have a question in terms of code and NOT user experience, I have the JS:
$(document).on( "click", "input:radio,input:checkbox", function() {
getContent($(this).parent(),0);
});
The above JS gets the contents from radios and checkboxes, and it refreshes the page to show dependencies. For example if I check on yes, and the dependency is on yes, show text box, the above works!
What I want to know is, if there is a better way to do the same thing, but in a more friendly way, as this is at times, making the pages slow. Especially if I do a lot of ticks/checks in one go, I miss a few, as the parent refreshes!
If you have to hit your server to getContent() then it will automatically be slow.
However, you can save a lot if you send all the elements once instead of hitting the server each time a change is made.
Yet, if creating one super large page is not an option, then you need to keep your getContent() function, but there is one possible solution, in case you did not already implement such, which is to cache all the data that you queried earlier.
So you could have an object (a map) which has keys defining the data you're interested in. If the key is defined, then the data is already available and your return and use that data directly from the cache. Otherwise, you have to hit the server.
One thing to do, you mentioned slowness as you 'tick' things back and forth, is to not send more than one request at a time to the server (with a timeout in case the server never replies). So the process here is:
Need data 'xyz'
Is that data already cached? if yes, then skip step (3 and 4)
If a request being worked on? if yes, push the data on the request stack and return
Send a request to the server, which blocks any further request until answer for 'xyz' is received
Receive the answer and cache the data in an object (map) and release the request queue
Make use of data as required
I check the request queue, if not empty pop the next request and start processing from (2)
The request process is expected to be run on a timer because (1) it can time out and (2) it need to run in the background (not GUI preemptive)

AJAX calls done during javascript initialization follow cache rules of browser however later on calls do not

I've recently started using JQuery AJAX calls to fetch some content within a document ready function. I am setting headers for cache control in the AJAX call that get overridden when a forced reload of the page is done (Chrome) which is exactly what I want.
Unfortunately later on calls to AJAX through user interaction after the page and content is completely materialized do not follow these cache rules.
For instance if I control-reload a page that initially accesses /dostuff/ during initialization with a cache control header set to an obscenely high max age time the browser overrides the cache control header and sets the max age to 0 which is nice.. it gives the
user a lot of control to refresh content.
Is this proper? Should I always expect AJAX calls that are part of initialization to override request headers the way I'm beginning to expect them to. It seems like there is a lot of room for inconsistency.
If I call the same URL later on it does what I want and the browser automagically adds in an if-modified-since header that helps me return properly from the server.
If I call a URL that hasn't been part of the initialization however.. like /dootherstuff/ .. It won't set the max age to 0 if the page initialized through a force reload.
I don't expect the be able to fix this problem since it appears to be working as it should be.. I would however like to know how to reliably detect if the page was force reloaded so that I can handle the cache control headers properly.
Resolving this issue using version keys on the URL that are fudged to deal with reloads, rather than actual content versions, will cause me a lot of grief and extra network traffic and processing time.

(Temp) Storage of JSON Search Results in Web App

I'm working on a search function for my Web app (HTML, JS & CSS only). I'm using jQuery's .getjson() method to retrieve data from a feed and display those results on a page. Inside of an .each() statement I'm adding HTML markup to the results making some of the elements links to outside sources.
The issue is when a visitor initiates a search on my Web app and clicks on a link from the results to an outside page, then uses the Back button on the browser to go back to the results page, all of the search results are cleared and another search needs to be initiated.
I'd like to temporarily save the search results so if a user clicks on a link from the results, then presses the Back button to come back to the app, all of the results will be available without the new for another search.
Taking this one step further, it would also be cool is the results for past searchs also persists so if the visitor continues to press the Back button, they can see all of their previous searches (with a given limit of course).
HTML5 sessionStorage seems to be ideal for this, but the information that I found points to a tedious coding solution. Can't I just save all of the json results as a JS object and have them re-rendered by my each statement when the visitor presses the Back button? I'm definitely open to using a code library or plugin for this problem.
http://brian.io/lawnchair/ is a good little library for API for persistence. You can use the same syntax as an abstraction for different storage options http://brian.io/lawnchair/adapters/
You have two ways to approach this issue, one is caching the results on your server and populating the view on-demand, and number two is like you previously mentioned - use sessionStorage. sessionStorage (IMO) has a very straightforward API. You can either use sessionStorage.setItem(key, value) or sessionStorage.getItem(key) -- other methods are available as well such as sessionStorage.key(index), sessionStorage.removeItem(key) and sessionStorage.clear(). It would probably be useful to include a cross-browser polyfill solution for sessionStorage, you can check out the "Web Storage" polyfills section at Modernizr: https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills -- Have fun :-/
Off the top of my head:
Every time the user searches, change the hash in the url to a unique string (e.g. 'search-{userInput}' ... you could of course just forget about the 'search-', but I like my urls in pretty). This should give you back-button support. Then:
Alternative A:
Listen for the hashChange Event, parse the window.location.hash and resend the request to your search URL. Theoretically, unless adding the timestamp to the URL or crazy stuff like that, the caching mechanism of your browser should kick in here. If not, it means an additional request, but that should be ok, shouldn't it?
Alternative B:
Extend your existing search query mechanism by caching the results to localStorage (just don't forget to JSON.stringify it beforehand and use a something-{timestamp} key). Then listen for the hashChange Event and pull the results from your localStorage. Personally, I wouldn't recommend this solution as you're clogging up the localStorage (afaik there's a limit at 2.5mB for some browsers).
You're probably going to have to find ways to circumvent missing browser support for at least the hashChange Event, JSON stringify/parse and LocalStorage, but I'm optimistic that there are enough libs/plugins out there by now.
You think too complicated: your search form most likely does not change the url! Use GET instead of POST and you have the desired result. Right now the browser has no way of knowing which state of the website you want to show and by default shows the first - the empty search form
Caching could be added as suggested, but that really is not the problem here

Categories

Resources