Flow: @PreserveOnRefresh or alternative missing

Created on 9 Feb 2018  Â·  17Comments  Â·  Source: vaadin/flow

When a Vaadin applications creates it's UI dynamically the use of @PreserveOnRefresh is needed, so the "state" of the UI survives a browser Refresh.

Please add @PreserveOnRefresh or an alternative

Thanks

enhancement feedback

Most helpful comment

Without @PreserveOnRefresh and extensive support in the framework manual coding of state in UI becomes very complicated.
For instance, Android UI Framework explicitly supports save/restoreState life cycle methods, moreover, state of UI fields that have id saved automatically.

All 17 comments

There are two reasons for why we haven't carried over @PreserverOnRefresh from Framework 8.

  1. It requires a slower and more complex bootstrap sequence. The only known good way of knowing whether a page is loaded from a new tab or by refreshing in an existing tab is to look at the window.name property. For this to happen, the initial response would have to only include a small JavaScript snippet that sends the value back to the server and the actual content would be delivered in a separate response.
  2. The way the new Router API encourages giving each view its own URL with parameters describing exactly what to show. This means that in many cases, everything needed to recreate the previous state is already present in the URL.

There are of course some cases when it would be beneficial to be able to actually preserve the previously used UI instance, so this is still something that we should look in to at some point in the future.

This is something we would definitely need for our Vaadin 8 application to be ported to 10.
Is this a big enhancement? We have the prime subscription and some development hours left.

All I can say without further architectural design is that it's not completely trivial because of the way Flow uses a single-request bootstrap sequence.

We would either have to come up with some sensible way of allowing the application developer to choose between single-request or dual-request, or alternatively keep using the fast and simple single-request boostrap and then somehow make it possible to adopt content from the old UI if necessary after the new UI has already been bootstrapped.

What is the actual benefit of @PreserveOnRefresh? I mean, when refreshing the page the session is still the same so one can retain all the needed info to restore the same UI.

It enables enterprise systems to not lose input data! It is heavily used option in our systems on Vaadin Framework.

We're also using Vaadin on enterprise systems so I'd love to help. In which cases may a refresh of the page happen while the user is inputting data?

For example, we have many grids with numerous fields to filter the data and input data is both bound to a bean (via Binder) which is kept in the session, plus the URL query is filled with the values so it is not only preserved on refresh but also it can be saved as bookmark or shared between users.

Could a combination of these prevent the need of a behavior which might cause a slower/complex bootstrap sequence? Can you describe your scenario or use cases for this kind of requirement?

I mean data entered for CRUD that is not yet saved. Form data cannot be set into URL, moreover enterprise systems usually have a lot of state in UI forms that should not be exposed to client-side.

Often, users try to refresh page to fix the problem with network or it can be accidentally refresh.

SFSBs seem more appropriate to retain state in enterprise applications, than UI; if your state is strictly tighten to the current browser tab, you can have a single query parameter to identity that in the current session and retain the state on refresh (e.g. on construction the UI will load a state from the current session based on that query parameter).

In the case of form data, if the refresh happens on accidental user action you can alert the user listening on beforeunload event to warn him of possible unwanted side effects (losing input data) and request confirmation to proceed (the user may want a refresh to start over).

Even this issue is related to browser refresh, I have similar issue when I navigate to different options of the main menu, by example in the App Bakery, If you are in tab "users” then you by example fire a filter, and then you go to tab “products” and come back to tab “users” then your last action (fire the filter) is gone, you comeback to initial list. Is there any way to avoid this, a way to keep the form in the way it was before navigating another tab? it seams that @PreserveOnRefresh could avoid this, but as doesn’t exist in vaadin 10 and I don’t see and alternative....

When you navigate throughout the app the HTML elements are detached, thus losing their state.

I don’t really see benefits of preserving the UI to retain user input data. Use session, local storage or cookies instead: it comes really easy now in 10 with Web Components.

@cqrendo I don't think that example has anything to do with @PreserveOnRefresh since the page is not reloaded when navigating between multiple views inside the same application. It's more about being able to preserve the state of one view while another view is active.

Another way of thinking of the users filtering example is that the state can be captured in the URL. /users would show the unfiltered list of users whereas /users/foo would correspond to filtering the users by "foo". In that way, the user could get back to their previous filtering state by using the back button in their browser, whereas the application's own navigation would lead to a clean state. This can be compared to how e.g. Google works: if you search for something, follow a link from there and then open google.com again, then your previous search query will not be there any more, but it will be retained if you either navigate back or open the search result in a new browser tab that you just close to get back to the search result.

Without @PreserveOnRefresh and extensive support in the framework manual coding of state in UI becomes very complicated.
For instance, Android UI Framework explicitly supports save/restoreState life cycle methods, moreover, state of UI fields that have id saved automatically.

I am in the way of migrating a huge Java Swing desktop application and one of the conditions of the customer is that to made the more similar possible to the existing functionality, one of the thinks that the actual Java Swing does out of the box is that you can navigate between different options of the menu and each new option you open you get a new button in a bar the represents that option that is there until you close, when you pulse the button you go back exactly in the same point where you were before going to another menu option. I know I can get similar behaviour using tab-sheets in Vaadin, but I is something must be coded , and as in the Bakery’s sample, is using views for navigating to different options I was wondering If you could get similar behaviour using the navigating/views way. I found that if you use web-explorer(firefox, safari...) tabs , you get similar behaviour, maybe this could be the solution. I just need to found how force a new tab from the vaadin App.

@cqrendo The most reliable way of opening a new browser tab is to use a regular link with target="_blank".

I think we could probably add a way to be able to keep the active route target state in place if wanted. Meaning:

  • when the user refreshes the page, the same UI state is used as what was previously opened
  • if the user opens the same page in another (same) browser window/tab, the old UI will be discarded

Where this would become weird is:
1) tab open with route /foo and make changes
2) open second tab with /bar
3) navigate tab to /bar -> /foo no effect on first tab
4) refresh the second tab /foo -> what should happen ?

Not sure how can we pick which UI state for /foo should be reused, from the first tab or second tab.
One option would be to default to then just _not reusing the UI state_, but also provide hooks for the application developers to handle this situation (or any UI refresh case) in the way they want to.

Another option would be that we enable the application developers to pick route targets that would use "two-step-bootstrap" always meaning that there is two roundtrips to verify whether the UI/route was already active (similarly as in Framework by checking window name to match existing).

Please, give better ideas. I see this feature as something we should enable for users to have without having to write lots of boilerplate.

Hi Pekka…

I wrote:

  1. In Vaadin 8 we override UI.init() to create our user interface and override UI.refresh() to check if user has changed parameters in the url, if so, we rebuild page with new parameters otherwise we keep current.
    Will we be able to mimic this behavior with the plugin/fix in Vaadin 10/11?

Must have picked the wrong words..

Basically we just want to be able to have the same functionality as with Vaadin 8

1 Every browser tab is its own, never pick up state or anything else from other tabs…
2 Be able to detect when the user hits Refresh or changes parameters in the URL... like we could in refresh(req) method in old V8 UI class.

On 18 Sep 2018, at 12.53, Pekka Hyvönen <[email protected]notifications@github.com> wrote:

I think we could probably add a way to be able to keep the active route target state in place if wanted. Meaning:

  • when the user refreshes the page, the same UI state is used as what was previously opened
  • if the user opens the same page in another (same) browser window/tab, the old UI will be discarded

Where this would come weird is:

  1. tab open with route /foo and make changes
  2. open second tab with /bar
  3. navigate tab to /bar -> /foo no effect on first tab
  4. refresh the second tab /foo -> what should happen ?

Not sure how can we pick which UI state for /foo should be reused, from the first tab or second tab.
One option would be to default to then just not reusing the UI state, but also provide hooks for the application developers to handle this situation (or any UI refresh case) in the way they want to.

Another option would be that we enable the application developers to pick route targets that would use "two-step-bootstrap" always meaning that there is two roundtrips to verify whether the UI/route was already active (similarly as in Framework by checking window name to match existing).

Please, give better ideas. I see this feature as something we should enable for users to have without having to write lots of boilerplate.

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHubhttps://github.com/vaadin/flow/issues/3522#issuecomment-422348033, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AD7CjMESagQLSxIMow3FGC9uKmFlf0o0ks5ucNCPgaJpZM4R_nR2.

@neerup the thing is that we cannot know whether or not the user refreshed things in V10+ without having a two-step-bootstrap. The second phase is used (in framework versions 7-8) to get the window.name and send it to the server so it is possible to detect whether it is refresh / init. So we cannot add back the refresh(...) method since we cannot currently know when the same window/tab is being refreshed.

And we're not going to go back to the two-step bootstrap as default for all Flow applications since it is a bad default to slow it down for the most common case (new UI opening) just to be able to support the refresh case. Thus we need to find and alternative _easy_ way for making it possible for you to have the same UX as before.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mcollovati picture mcollovati  Â·  4Comments

stefanuebe picture stefanuebe  Â·  4Comments

pleku picture pleku  Â·  4Comments

knoobie picture knoobie  Â·  4Comments

anezthes picture anezthes  Â·  4Comments