Routing with preserving previous view/viewModel

Hey,

first of all congratulations for the alpha release.

My question is about the router. Let’s say you have something similar to Gmail inbox:

I searched for “C#”, selected some mails, scrolled down to the right and to the bottom.

When I open the mail the route and the view changes.

Now when clicking the back button in the browser I’m on the exactly same view as previously (filters, scroll-position, selection of mails, …).

It looks like Gmail is working with some kind of view-stack they preserve in background while navigating.

Is it possible to achive this kind of functionality with the new router in Aurelia 2?

Best regards, Stefan

1 Like

Is the Info though really persisted in the Route or in Localstorage? I would assume the second, so when you go back you’d check the Localstorage content on activate and re-apply position and selection. Doing all of that just with a simple service might not be enough as as far as I remeber they’re approach also works with a hard refresh

1 Like

I think you may be able to do it via stateful:

<au-viewport stateful>
1 Like

I don’t think it’s persisted in LocalStorage/SessionStorage. I.e. if I change the subject and the color of a mail using Dev-Tools, open a specific email and click back this subject has still the changes I made (text & color).

During page reload the filter is persisted but the selection, scroll-position, … aren’t.

Thanks bigopon!
Only by changing stateful on ViewPort nothing changes. Do you know if I need to configure anything else? Or am I too early to work with the router because it’s still a work in progress?

In our business application built with Aurelia v1 we’ve created this functionality by ourself as it is quite important for us.

We use a navigate method with three options (no support for different view-ports):

  • add the created view to the view-stack
  • clear view-stack first and add the created view afterwoods
  • replace the current view in view stack with the created view

When clicking back in the browser we look whether there are any more views in the stack. If this is the case we remove the last view from the stack and show the previous one. If there are no more views, we use the information from the browser history (same as the current router).

Well ok so the pages contain the logic which would be like the router viewstrategy of not replacing but keeping the old state in place along with the components instance right?

Exactly. The code executing the navigation knows whether to keep the view or not.

For example:

  1. you are in mail list view and click on a mail to open it => keep mail list view.
  2. you are in the mail list view and navigate to the task list view => drop mail list view

So case one could also be a child router hosted by the mail list view? Essentially that way youd keep the state around and just render an additional au-viewport or not in case of default. Otherwise the AppRouter on the second case switches the whole display. Pretty much what the V1 skeleton demo was doing with the recursive rendering right?

Thanks for your support in helping me find a solution.

You are right, for the two examples this would be a possible solution. Especially since the two views have a contextual relationship.

However, in our existing application the case is not that simple. We have about 140 views that can be navigated between. There may be 5 views involved for which the state must not be discarded.

If I understand the system with the child routes correctly, a child router would have to be implemented in each view, which defines all possible child routes, which is not so easy to solve. Sometimes embedded elements in a view trigger the navigation, of which the parent view knows nothing at all.

This is one of the reasons why we implemented a stack router a few years ago that solves all this without requiring a special additional implementation for each view.

Do you think our requirement is too specific to be solved in a general router?

Gosh no, I think the concept of a Stackrouter is fantastic and tbh I didnt fully understood your use case. But with the recent reply it makes fully sense. So hierarchy wise all/certain Views are on the same lvl but could be “overlayed” and “reverted”.

@jwx is this something the new router could cope with?

Yes, the stateful (viewport and component config) and statefulHistoryLength (router config) cover these use cases. They’re however not present in the current implementation.

In Aurelia 1 we solved this and other scenarios implementing a cache of model-views.
In the router we register a wrapper component, reinstantiated at every navigation, that reads the cache, finds the correct view-model from previous activations and uses a compose with view-model.bind to recreate the previous state.
Unfortunately the new au-compose doesn’t seem to support view-model.bind :frowning:

I don’t want to seem impatient, but is it predictable by when the feature mentioned by @jwx will be available for testing?

The plugin from @jwx has already been published and should have this feature included. Please have a look at:

@bigopon thanks!

I’ve created a new project, added the aurelia-direct-router package and replaced the the RouterConfiguration like mentioned in the router documentation. Worked!

Than I added the “stateful” attribute to the au-viewport tag. Now I only can navigate once. If I click another navigation item, an error is thrown:

In the aurelia-direct-router repo I found the doc-example which should work with stateful components. Unfortunately, I could not get it to work.

@jwx can you give me a hint what else I have to configure?

I’ve uploaded my simple sample to GitHub https://github.com/stenet/au-20210526

1 Like