What is the expected behavior of Javascript when you do a soft refresh on a web page?
I know that when you refresh a page, most web browsers will preserve values entered into form elements on a page. But it becomes harder to predict what will happen on a refresh when half of the page is dynamically generated.
My question is a little more general than that, though. I want to know what the prescribed behavior is for a web browser when a page will dynamic content is refreshed. In particular:
What Javascript gets rerun.
How is the DOM altered on the refresh.
How are form values "floated" to the proper place in the DOM after a refresh.
What other quirky stuff goes on?
If you leave a page by clicking on a link or entering an URL into the navigation bar some browsers try to pause the page and resume it once the user comes back. This technique is known under different names:
Safari/WebKit: Page Cache
Firefox: Back-Forward Cache
Opera: Fast History Navigation
For the page it looks as if the user has never left it. However not all pages can be paused. Especially pages with plugins, pages served using HTTPS and all pages with an unload event handler are ignored by a page cache.
If the page cache is not used, the page is reloaded from the server. Browsers might fill in form fields and restore scroll positions.
A reload = a complete re-request. (shift + reload = reload all js and css files from server)
The browser might also remember name="" value="" pairs, and tries to pre-populate the fields based on the remembered pairs. It is not about trying to populate exactly what fields are in what pixel or whatever.
I refresh pages all the time when developing, all javascript is re-run as if the page is loaded anew. I do not believe the change events kick off in the page due to remembered values.
This is also true for firefox -> this frame -> reload or IE right click on a frame and reload.
Chrome does not allow single-frame reloads.
Related
I'm working on a site that provides web access to to legacy data.
The basic flow is for the user to select a query form from a menu, fill out the form, and submit it. The server generates the appropriate HTML and returns it to the browser. So far, so good.
Some reports can take some time to generate. For those reports I display a "processing" indicator when the form is submitted. This indicator is a normally hidden <div> containing an animated icon.
The problem comes when a user uses the browser's Back button to return to the query form. When the browser re-displays the page with the query form, the processing indicator is still visible. The only way to get rid of it seems to be to refresh the page at that point.
Is there any way to hide it after the Back?
You could set a JavaScript event to automatically remove the indicator after the page loads. That way, the indicator won't display unless the script later tells the indicator to show. In order to avoid never displaying the indicator, you could place the code that displays the indicator after the event that automatically hides it, both occurring on the page loading.
I finally have a solution for this that is working well enough in this application.
Some browsers, like Firefox, fire a document.focus event when the page is re-displayed. Others, like Safari, fire a window.popstate event instead.
I now hook both of these events and it works as expected 99.9% of the time.
As far as I could find, you should be able to use pageshow window event:
The pageshow event is sent to a Window when the browser displays the window's document due to navigation.
This includes:
Initially loading the page
Navigating to the page from another page in the same window or tab
Restoring a frozen page on mobile OSes
Returning to the page using the browser's forward or back buttons
<!DOCTYPE html>
<script>
window.addEventListener("load", console.log);
window.addEventListener("pageshow", console.log);
</script>
<p><a href="https://html.spec.whatwg.org/multipage/">Navigate
away</a> (then come "Back")</p>
See also:
Can I use "pageshow"?
Let's say I want to stop all videos from playing in the browser so while on the youtube.com page I run HTMLVideoElement.prototype.play = function() {}. I click around and since it doesn't do a full page refresh the JS persists.
However, if I press refresh, then my JS is reset and HTMLVideoElement.prototype.play once again points to native code. Is there a way to persist that command even on page refreshes?
JavaScript is run anew on every page load. This is by design and cannot be changed. Use a browser extension or a userscript that runs the script on each page load.
Things run on the console will be lost when the page navigates away (that includes navigating to the same page you're already on).
Is there a way to persist that command even on page refreshes?
Yes. So long as it's a page you control (so, not youtube.com) you can persist a setting before and after a page refresh by:
adding a hash fragment to the URI;
adding a query string to the URI
placing a cookie
using the window.name property
using HTML5 Web Storage (localStorage / sessionStorage)
By using javascript to query any of the above after the page reloads, you can re-establish the setting you had in place prior to the page refresh.
When accessing an external page from a Cordova app, then coming back to app with back-button, the app page is empty, or more precisely, everything that was dynamically added to the page is gone.
This seems to be the case whether the link is a native <a href="..."> or is accessed via window.open(), or via cordova.InAppBrowser.open(). The only way it does not happen is when the actual browser is specified via "_system" parameter.
Is there a way to prevent this, or is it normal behaviour ? Should I simply rebuild the dynamic page upon returning ? I could do that, but no event seems to be fired on return, not even a pageshow.
Navigating back refreshes (reloads) the page...so anything dynamically added to the page will correctly be gone. You could use hash tags on the URL for simple information or localStorage for more complex information about the page state and re-populate the page based on it when it reloads.
pageshow most like isn't firing because of some assumption being made in the JS code. Try listening to the $(document).ready for debugging purposes. It could also be caused by the issue described here (because of caching): 'pageshow' is not received when pressing "back" button on Safari on *IPad"
Specifying system causes the page to open in a new window...so that's
Problem: I have 2 frames, each with a form. One frame is for navigation, the other is for 'doing stuff'
I want to click something in Frame A (Navigation frame)
and get the following behavior:
1) Submit the form in Frame B (to save changes)
2) Change the location of Frame B after saving changes (Navigate)
3) Frame A should not submit/reload
So far, I can accomplish either of the above goals (1 or 2), but I can't save changes AND navigate in the same act. I can get one or the other to work but I don't understand why.
Frame A (Navigation) uses code like this:
Navigate to Something
Javascript for rowClicked:
top.frameB.document.getElementByID("frame_b_form_id").submit();
top.frameB.location="new location, so we can navigate";
return false; // Keeps frame A (Navigation) from reloading
My problem: If I don't change the location, my form in frame b submits and everything works perfectly. But I want to navigate! If I add the top.frameB.location javascript, the navigation works, but the form in the other frame doesn't get submitted!
I'm sure there's something simple I'm missing!
EDIT:
This problem is in the latest Chrome and firefox browser versions ... This code seems to work as desired in IE 11, IE 8, FF 3.03
Last EDIT:
I never figured out how to do this consistently across browsers. Fortunately, I realized that there was a better way to accomplish what I wanted. The page was generated by mod_perl code, so 'submitting' the page caused not only the data saving, but also page re-generation (of the page the user was already on). Navigating after that meant the server wasted time generating the page the user was navigating away from, on form submission. The real fix was in my perl code so that a form submission triggered navigation ... I used javascript to add hidden inputs that were included with the form - the hidden inputs tell the server that after saving, generate a different page (ie navigate) and return that, instead of re-generating the page the user just visited & saved.
A website contains a "random" link, which loads a url that returns a 307 redirecting to the url we want. It works fine: click it and you load a random page. The problem is that each time you click it, the browser assumes you're loading the same page: so if you're on the homepage, then you follow the random link 5 times, then you press back, you'll be taken all the way back to the homepage, with no way to find the random pages you were just looking at. I want to modify this behavior so that users can access previous random pages via the back and forward buttons.
I don't own the website, so I can't just change the redirect code.
Here's what I've tried, all of which has failed.
Predicting what would be redirected to. While somewhat possible, there would be no way to avoid failure in up to .1% of clicks, and it would react very poorly to unexpected events, like a page that's published a day late, let alone a sit structure change.
Loading the 307 page via ajax. The request stops at readystate == 2 and I can't access the location header.
Cancel the click event and instead set location.href = random_link.href. This has no effect - the new page still doesn't go into history.
Have the new page call history.pushState. This successfully adds the page to history, but I can't find a way to distinguish between new pages and ones being opened via the back button, so the history quickly becomes very corrupted.
Keeping my own history in localStorage. As above, I can't tell when the back button is being used.
I'm working on a solution that I'm pretty sure will work, involving loading the page in an iframe over the existing page and using a background process and messaging to work around the fact that content injections from chrome extensions can't access window.parent from within iframes. And using the history API to reflect the current iframe's URL in the address bar, and get the back and forwards buttons to apply to the current iframe where appropriate.
While I'm pretty sure the last solution can be made to work, it's a hideously complex and heavyweight approach to what seems like a simple problem. So I thought I'd ask you guys before I continue: any other ideas?
Have you tried storing the locations in localStorage, then hi-jacking the back button ?
I am sure you know how localStorage works, for hi-jacking the back button you can refer to this : Is there a way to catch the back button event in javascript?
T.