Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@PreserveOnRefresh or alternative missing #3522

Closed
neerup opened this issue Feb 9, 2018 · 17 comments
Closed

@PreserveOnRefresh or alternative missing #3522

neerup opened this issue Feb 9, 2018 · 17 comments

Comments

@neerup
Copy link

neerup commented Feb 9, 2018

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

@Legioth
Copy link
Member

Legioth commented Feb 9, 2018

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.

@neerup
Copy link
Author

neerup commented Feb 9, 2018

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.

@Legioth
Copy link
Member

Legioth commented Feb 9, 2018

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.

@heruan
Copy link
Member

heruan commented Feb 12, 2018

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.

@jreznot
Copy link
Contributor

jreznot commented Feb 12, 2018

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

@heruan
Copy link
Member

heruan commented Feb 12, 2018

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?

@jreznot
Copy link
Contributor

jreznot commented Feb 12, 2018

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.

@heruan
Copy link
Member

heruan commented Feb 12, 2018

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).

@cqrendo
Copy link

cqrendo commented Jun 23, 2018

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....

@heruan
Copy link
Member

heruan commented Jun 23, 2018

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.

@Legioth
Copy link
Member

Legioth commented Jun 25, 2018

@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.

@jreznot
Copy link
Contributor

jreznot commented Jun 25, 2018

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.

@cqrendo
Copy link

cqrendo commented Jun 25, 2018

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.

@Legioth
Copy link
Member

Legioth commented Jun 27, 2018

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

@pleku
Copy link
Contributor

pleku commented Sep 18, 2018

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.

@neerup
Copy link
Author

neerup commented Sep 18, 2018 via email

@pleku
Copy link
Contributor

pleku commented Sep 18, 2018

@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.

@pleku pleku modified the milestones: V13 Candidates, V14 Candidates Jan 15, 2019
denis-anisimov pushed a commit that referenced this issue May 2, 2019
Addresses #3522. If the @PreserveOnRefresh annotation is added to a routable component, then router will detect on refresh in the same browser/window tab whether a component has already been created previously in the session, and if, reuse that.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants