I am using Firefox, and I have noticed something interesting while working on my website. One page has a table of information, but also maintains Javascript variables indicating the table's contents so it can look up information more easily.
When I navigate away from the page by typing in a URL, then hit the back button to return, I have noticed that the page seems to retain its state. The table still has the same contents as when I left, and further interactions with the page indicate that the Javascript variables have maintained their values as well.
I had assumed that my $(document).ready(); functions would run again when the back button was hit, but this is clearly not the case as I wrote those functions to ensure the page is its initial state, regardless of the page's current content.
I think it is perfectly acceptable for the page to be restored this way as long as I can depend on the page being restored properly. If instead, the page is restored to its initial state, that would be acceptable as well.
Is it safe to rely on this behavior? Would I be better off using something like onunload to ensure that the page's state is not saved? Should I just assume the browser will do things properly?
I would say that my website's state is defined by the HTML on the page and the contents of Javascript variables. It uses AJAX (or I guess technically AJAJ) to interact with PHP pages, but all interactions are discrete transactions. The only state/session needed by the server are login authentication cookies, which should be unaffected by this.
Related
Suppose you have some kind of listing and you allow this listing to be rendered via CSS either as a list or as a grid (via a varying CSS class or data attribute). Since this is purely a rendering issue it required not (re)processing by the web server, thus you can also simply implement the switch on the client side via JavaScript.
However, suppose you want to save the client's view mode choice, e.g. in the localStorage. Now when the page is rendered, the appropriate view mode needs to be restored.
But what is the best practice here in order to prevent the switch from the default view to the saved view to be visible when the content is above the fold?
Consider the following crude example: http://jsfiddle.net/yaubvq8d/27/
Here the JavaScript for changing the view mode and also loading the saved view mode from the localStorage is at the end of the body, which is obviously not ideal. To visualize the problem I also integrated an externally loaded JavaScript, that blocks rendering of the page for 2 seconds - so it takes at least 2 seconds, before the JavaScript for managing the view mode is actually executed. During these two seconds you first see the default view (which is the grid view) and then it would switch to whatever view you had previously selected (to test this you obviously have to click on "List" first and then run the fiddle again).
The only obvious solution I can think of is defining the view mode in a parent container (let's say the body) and then execute the JavaScript to load the view mode from the local storage right after the starting tag of the parent container.
But are there any other best practices, that I might miss?
It seems that Framework7 remove DOM elements of previous pages and only keep the previous one. This is problematic since the state is loss as not all interactions are stored in the backend. For example:
Page A > Page B ---> Nothing is removed
Page B > Page C ---> Page A is removed
Then when user click back twice, Page A only shows up only if Page A was fully loaded before addView() function is called. If Page A is loaded afterwards, user will not be taken back to Page A.
Is there any suggestion on how to solve this issue? I looked at the API document and didn't see any option to make sure this doesn't happen.
Update
I managed to get it to go back to Page A by making sure div[data-page] exists before the view is loaded. However, it completely lost the state when returns back to Page A, which is completely useless. Without being able to disable this behavior, I will have a lot of extra code to store every interactions taken by user whether it's done in UI or backend. Let me know if you have any suggestions.
Update 2
I also reported the issue on GitHub. The framework should cache final state of the page rather than original state.
https://github.com/framework7io/Framework7/issues/1985
What happens when a JQUERY MOBILE page is refreshed?
I use ajax to fetch data in a variable called "json" on page1, when user clicks a particular dynamically generated element, i store the id of clicked element in a session variable and changePage() to a new JQM page2 where i use json.thepropertyiwant to generate a list, everything works fine, even back and forward buttons work perfectly however if i refresh page2
then json.thepropertyiwant becomes undefined here is the error i get:
Uncaught TypeError: Cannot read property 'responseData' of undefined
i am using a multipage in a single html5 page model
edit:
I have used variable name json and not JSON i just typed it like
that to emphasize, however now i think that was foolish!
I have also figured my problem. My mistake was that i was assuming
page refresh would call pageinit for the page i am on but it works
no differently than a normal html page refresh and triggers
document.ready each time and then pageinit for the page i am on.
Is there a way to listen to a
pagerefresh event and override its normal functionality?
I believe that you generate the dynamic content of page2 in some event.
I believe that the event is pageinit or pagecreate. Those events fire only once (if you have ajax page load set to true).
What happens is that you request the data when you load page1 (something like pageinit?)
When you refresh page2, the data is not there because the event that you request your data in, is not firing, which is completely normal, because when you refresh page2, page1 has nothing to do with it. Post the section of your code where you request your data, and the section where you generate the dynamic content for page2 for more.
Hmm... there's a few issues going on here.
For starters, don't use a variable called 'JSON'. That's no good - there's already a global object called JSON which is used for parsing and encoding JSON! You could accidentally overwrite it.
As you discovered, if you store data in a variable in javascript - that variable is only in memory for the current page. If you refresh the page, then that variable will no longer be in memory.
But that's not really anything to do with jQuery Mobile. That's just how web browsers work - javascript structures created in-memory are not persisted between page refreshes.
Generally you need to save the data yourself using localStorage or cookies for it to persist between page refreshes.
Typically you don't refresh a jQuery Mobile app anyway. So the previous point is generally not too much of an issue. A user refreshing the page is like rebooting the app.
The app should when it starts reload any data that it needs, i.e.
from localStorage, from cookies, or make some new ajax calls to
reload. You would have to program that logic in.
I want to change html without reload. I do it like:
$('#left_menu_item').click(function(e) {
if (!!(window.history && history.pushState)) {
e.preventDefault();
history.pushState(null, null, newUrl);
}
});
It works correctly. But if I want to go back with "Back" button - browser change url on previous, but it not reload page. Why?
this behaviour is expected and is in accordance with the specifications of manipulating the history stack.
this is a relatively complex problem to explain. but in short think of it as this: any history entry the user pushes on the history stack (using pushState etc) doesn't merit a page load when you move from it because it is considered a fake (user generated) history entry.
why?
this behaviour is a good thing and is consistent with the intent of giving the developer more control over the page without being forced to reload it (think of it like ajax: you can do things that were previously only possible by page reloading like fetching data but now you can do it without reloading the page using the XMLHttpRequest object).. if you want to mimic the behaviour of reloading the page when clicking the back button.. you can simply call location.reload() when you handle the window.onpopstate event
how?
this may be outside the scope of your question but i just wanted to put it there to describe what we're talking about
let me explain by using an existing example here (excerpted text will be italicised):
Suppose http://mozilla.org/foo.html executes the following JavaScript:
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
This will cause the URL bar to display http://mozilla.org/bar.html, but won't cause the browser to load bar.html or even check that bar.html exists.
think of it as that you are creating an entry in the history stack that is not associated with an actual page load.. rather a 'fake' page load (ie you are just using javascript to manipulate the dom and insert html)..
Suppose now that the user now navigates to http://google.com, then clicks back. At this point, the URL bar will display http://mozilla.org/bar.html, and the page will get a popstate event whose state object contains a copy of stateObj. The page itself will look like foo.html, although the page might modify its contents during the popstate event.
the point here is that bar.html is a fake history entry that sits on top of the original http://mozilla.org/foo.html.. so you will see on the url http://mozilla.org/bar.html but the contents will belong to foo (in this example notice that we didnt manipulate the content of the dom when we pushed bar.html.. if we did like in your example.. then that content will also show up). the key thing here is that the page reloads!.. because we are serving a page that has a genuin entry on the history stack (even if on the url.. we are displaying a url that is associated with a fake entry on the history stack).
also separate this discussion from the page manually handling the popstate event.. that's a different story and will just complicate things.
If we click back again, the URL will change to http://mozilla.org/foo.html, and the document will get another popstate event, this time with a null state object. Here too, going back doesn't change the document's contents from what they were in the previous step, although the document might update its contents manually upon receiving the popstate event.
here.. the page will not load!.. that's because we are making the transfer from a fake history stack entry to the real one (and the real one was already loaded in the previous step.. so the page reloaded and that's it).
that's it for the example. the concept is kind of hard to explain and i encourage you to test your code by clicking through a combination of real and fake pages and you will see a pattern of when the page actually loads and when it doesn't..
window.onpopstate = function(event) {
if(event && event.state) {
location.reload();
}
}
This is what I use :)
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.