ionic-team / ionic-framework

A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript.
https://ionicframework.com
MIT License
51.09k stars 13.51k forks source link

feat: ion-nav / ion-router: ability to swap current view #21316

Open cjorasch opened 4 years ago

cjorasch commented 4 years ago

Feature Request

Ionic version: [x] 5.1.0

Describe the Feature Request

Currently there is not a way to swap the current view in the navigation stack vs. pushing or popping.

For example, a simple contact management app might use a route '/contacts/:contactId'.

If the app provides a Next button then it is not clear how to show the next contact with the appropriate url while avoiding continuing to push new views onto the navigation stack.

Currently it keeps adding new views to the stack so the user experience would be:

Swapping views in the stack is common for many mobile apps (email, contacts, etc.)

Describe Preferred Solution

One possible approach would be to add swap to the values for RouterDirection. This could then be passed to ion-nav so it could swap the view vs. pushing a new view onto the stack.

ion-nav could also be updated to expose a swap method.

nhoctanker commented 4 years ago

I hope this feature . I have two tabs Products . Profile
Router :
tabs / products tabs/products/:id

tabs/profile On Ionic 5 When i go to Products tabs -> i list a link in Products page to go to tabs/profile . I can't swipe back to Products page

How i can swipe back to tabs/products when i go to new router tabs/profile ?

vicb commented 2 years ago

Hey,

If you use a <ion-router-outlet> instead of a <ion-nav> then there is no stack and you will effectively "swap" views.

However because the url is updated when you navigate to the next contact you might still have to "user needs to back through all of them" (I don't exactly understand what you mean by this).

cjorasch commented 2 years ago

My goal is to be able to use a "stack" metaphor like the one that is implemented by <ion-nav> but to also handle changing an item in the stack vs. just push and pop.

This is a common mobile navigation style and used by apps like iOS email:

The "back through all of them" comments relates to how it works now using <ion-nav>.

The ionic back button is used to pop up a level in the stack which is sometimes different from browser back.

vicb commented 2 years ago

Some thoughts I have on what you are trying to achieve:

The "back through all of them" comments relates to how it works now using .

ion-back-button pops element from the nav stack.

If you want to use it there should be one element on the stack (i.e. the root) and then going back would bring you back to the default URL which would be our list.

In this case you probably wants the ion-nav not to have anything to do with the router by adding the no-router attribute to it. You can load a new message by calling nav.SetRoot(<your previous/next message>).

But then what is the point of using a ion-nav if you are not using the stack ? You could only use a Message component loading a message and a ion-button to come back to the list ? With a nav navigating to an already created view is probably faster because you don't have to re-create it but also it consumes more memory as all the views are kept. If browse through 20 message you'll have 20 views in memory (it's probably not a problem on desktop but might be on mobile).

I hope that it could help you.

cjorasch commented 2 years ago

Thanks for the suggestions. Makes sense for a simple case.

The more complete use case I am working on involves multiple starting lists with more levels of depth. It is more of a database oriented SASS application so you end up with stack navigation like home => account list => account detail => account contacts => contact detail => contact address. <ion-nav> handles this very well including things like preserving page state in the stack, ability to pop back multiple levels, etc. The only thing missing is the notion of swapping a node in the stack.

vicb commented 2 years ago

I fail to see how swap would help. You would still have to go through all the views if you navigate back. If you don't allow navigate back (ie only an app not a web app) then you can probably use a stack and not the ion-back-button but a custom implementation. Also what does swap would bring more than the current setRoot ?

cjorasch commented 2 years ago

Swap would help for detail pages that are children of lists.

home => account list => account => account contacts => contact A swap to contact B swap to contact C back returns to account contacts page

vicb commented 2 years ago

I believe setRoot(B), setRoot(C) would work and "swap". Again only caveat would be browser back button.

On Wed, Feb 9, 2022, 21:24 cjorasch @.***> wrote:

Swap would help for detail pages that are children of lists.

home => account list => account => account contacts => contact A swap to contact B swap to contact C back returns to account contacts page

— Reply to this email directly, view it on GitHub https://github.com/ionic-team/ionic-framework/issues/21316#issuecomment-1034505883, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB4X4QBASEHZLZYQOQ7GTLU2NDXHANCNFSM4NC6DHXQ . You are receiving this because you commented.Message ID: @.***>

cjorasch commented 2 years ago

If you set the root then Ionic does not think you can go back so the ionic back button, swiping, and other stack management features do not work.

Also, there is lots more going on in the navigation stack with <ion-nav> than simply routing. It maintains the full rendered content of the pages in the stack including full state information (scroll position, expand/collapse, inputs, loaded data, etc.). This enables smooth back navigation and is key to things like animation. It also supports things like tabs where, for example, you could have a contact detail page with various tabs for different content and a url for the tab pages.

It sounds like your suggestion is "don't use <ion-nav>" but it is actually a pretty good tool for the page stack paradigm.

It is not the best approach for all apps and there are many cases where simple route based navigation is a better approach.

The notion of swapping the page is also something that exists in the underlying browser location api

vicb commented 2 years ago

I just happen to work on the router a lot lately on got interested in nav. Understanding your use case helps me get a better understanding of ion-nav.

I'm still not sure what you mean by swap. If you navigate to contact A and swap to contact B, what would be the content of the stack then ?

If thought it would be [contactB] only which is why I suggested setRoot but in this case you are right swipe will not work. Because swipe pops the stack has to be [contactA, contactB] for it to work but it is what we have today - or are you also suggesting to change how swipe works ?

cjorasch commented 2 years ago

Think of nav as maintaining a stack of active pages.

Nav lets you:

I am not suggesting a change to swipe

vicb commented 2 years ago

You swap C to D on the stack (proposed new feature). Now the stack contains D on top of B on top of A. Back would return to B.

Thanks, that makes sense now.

I don't think the code of nav would really support adding/removing in the same transition and it would require quite a few changes.

Maybe one thing you can try (provided you always swap at the end):

await nav.push(D);
await nav.removeIndex(nav.getLength() - 2);

It should still be possible to do that for whatever index as long as you maintain a map contact -> index

cjorasch commented 2 years ago

That is an interesting suggestion - I will try it. I think it would result in different behavior between the browser back button and the ionic back button but maybe that is ok.

In the past I was trying something similar with a combined nav.pop() and nav.push() but ran into lots of problems with transitions.