nativescript-angular
nativescript-angular copied to clipboard
Open/close modal view from app.component breaks navigation
If there is no issue for your problem, tell us about it
When you open a modal view from app.component and then close it, the default router navigation seems to repeat onto itself. Pressing the back button navigates back to the same home page. Connected to https://github.com/NativeScript/nativescript-angular/issues/1502
Which platform(s) does your issue occur on?
- Both
- emulator or device.
Please, provide the following version numbers that your issue occurs with:
- CLI: 4.2.2
- Cross-platform modules: 4.2.0
- Runtime(s): 4.2.0
- Plugin(s): (see playground example)
Please, tell us how to recreate the issue in as much detail as possible.
Use the playground example below. The login modal page is opened at the start from app.component
- Tap on "Successful Login" -> The modal will close
- Tap the back button -> One navigation to the same home page will execute
Note: Implementing one navigation inside the modal view seems to fix the issue.
Is there any code involved?
https://play.nativescript.org/?template=play-ng&id=2ceg6i&v=2
This is causing some serious issues on a project I'm working on. Is there a working fix?
@Eonfuzz Yep, as I mentioned in the issue - implementing ti as a modal view with navigation in it works around the issue. Here is an example - https://play.nativescript.org/?template=play-ng&id=XfRwGm&v=8.
What if we added an option like disableNavigation: boolean to ModalDialogOptions that lets us control whether or not closeCallback executes this.location.back():
https://github.com/NativeScript/nativescript-angular/blob/6155f022cb05dfbd0d6e3b19aab53561f14f65f6/nativescript-angular/directives/dialogs.ts#L132
This new option, disableNavigation, would be false by default as not to interrupt the current working use cases of the modal but give flexibility to others to control their own navigation after the modal closes.
@MartoYankov thanks for the quick reply!
I currently do have multiple navigation steps in the modal view, if there is only ever a single navigation inside the modal there is no issue. But if there is more than one navigation entry it causes the weird navigation behaviour.
On hindsight, it may be a different issue entirely - but it almost looks like it creates a seperate routing instance in addition to the original one.
Check out this gif, I open the modal when I click on [Roller Blinds] at the bottom left hand corner.
After going back to the previous route, you can see the app hangs and pauses before the route starts going haywire.
I'll try to put together a playground that reproduces the issue, but basically...
- The modal is inside a lazy loaded module
- Almost identical to the documentation, except the modal has more than one route
@Eonfuzz Thanks for reporting this. It definitely looks like a different bug. If you can reproduce it in a simple playground and open a new issue it would be great.
@MartoYankov I'm not 100% sure that my case illustrates the exact same problem, but I got here looking for a way to have a global custom-dialog service. I thought I nailed it when I said "ok, I'll handle the showDialog in the root (app.component) and listen to actions dispatched from my store, and make the decission to show the dialog there, in one place, with whatever parameters I need to"
My use case: I need to show dialogs to the user, with custom content/design (not supported by the standard dialogs initialization options), depending on certain conditions known either A) at an interceptor level or B) in my store/state management, as a result of different dispatched actions.
And having to repeat code like this.modal.showModal(MyDialogComponent, myDialogOptions)
in 10-20 or more different components is not really acceptable. It should be done at a service level or, like I said, from state management or even from http interceptors. While it would still be possible to also send the ViewContainerRef of the 'current' component to my store, along with any other payload, and use that ref, that's still unacceptable design for my code, having to send a ViewContainerRef in all the payloads of any store action dispatched. Plus, that would be even more difficult to achieve when having to simply trigger the dialog from an interceptor, no state management involved.
I don't really understand the design decision to have to pass a ViewContainerRef to the custom dialog, why wasn't it made to work without that, like the standard dialogs do. In my oppinion, a dialog needs to be absolute, independent of any view/component. But that's maybe because I don't know how native mobile development really works. Also, I'm a NativeScript newb here, just got started a couple months ago with my first app.
Anyway, long story short (too late 😄) in case it helps and is a valid reproduction, I made a repro here: https://play.nativescript.org/?template=play-ng&id=AruVA6 Not sure if it satisfies this issue 100%, but it seems like more or less the same behavior: getting redirected to '/' when dismissing the dialog. So, once the app opens on the '/' route (where I render the Home component):
- Navigate to the
/about
route by tapping the "About" button - Tap on the "Open dialog" button. This tells the app.component (through a service) to open the dialog.
- Dismiss the dialog.
- NativeScript redirects you back to the root '/' route.
Expected behavior: remain on whatever route you're on.
@kkoates: What if we added an option like disableNavigation: boolean to ModalDialogOptions [...]
I guess this would be the most viable solution, in order to not introduce breaking changes
P.S. On the NativeScript Community slack workspace, someone said that I could potentially use topmost()
to open a custom dialog, without passing a ViewContainerRef, but couldn't find anything on that when I googled it. And didn't want to bother that person further. Is that possible?
@MrCroft Thanks for the scenario.
In iOS dialogs are modal views. There is no equivalent to the Android dialogs, so we are always using a modal view. Also, in iOS a modal view (presented view controller) is always shown by another view controller (presenting view controller). The ViewContainerRef is important for modal views that embed navigation in them. It doesn't make much sense for dialog like popups. Currently, the API doesn't provide distinction between the two. We are still discussing this at the moment, so I don't think we can provide something like this in the next release.
The issue with redirecting to '/' is logged as a bug in the router and it should be fixed with the next release of nativescript-angular
. As I wrote in the issue, there is a workaround - make one navigation inside the modal view.
I'd like to add that if you call Router.navigate in dialog callback, you will go to the new page and will immediately return back to the previous page.
this.dialog.showModal(SomeComponent, { fullscreen: false, viewContainerRef: this.viewContainerRef, }).then(() => { this.router.navigate(["some path"]); });
EDIT: I decided to open my own bug: https://github.com/NativeScript/nativescript-angular/issues/1661
The modal seems to seriously break navigation in a variety of ways, here are problems I'm observing that I think are related:
With page-router-outlet
:
- Closing a modal that was opened on a page navigated to with
skipLocationChange: true
, will cause a navigate to the previous page - Closing a modal that was opened on a page navigated to with
replaceUrl: true
, will a navigate to the previous page
With router-outlet
:
-
RouterExtensions.canGoBack()
will cause a crash within the dialog, and after the dialog closes until a navigation action is performed. (TypeError: Cannot read property 'states' of undefined File: "file:///data/data/org.nativescript.nstest/files/app/tns_modules/nativescript-angular/router/ns-location-strategy.js, line: 227, column: 22
)
The issue I reported (this.location.back();) that was moved to this issue is now resolved. The back navigation has been removed. I verified this on 7.1. It may be worth updating to latest to see if everyone else's issues have been cleared up.
@kkoates : it has not been removed. It has been renamed to "this.location._closeModalNavigation()", see https://github.com/NativeScript/nativescript-angular/blob/06bbcae7879c689ab3cfab6535a31e7671dc5277/nativescript-angular/directives/dialogs.ts#L133 So this is still happening.
@NickIliev : do you think it would be possible to add the capability to disable that side effect? In our situtation this is really a problem because we use the route to store some parameters that allow us to easily manage our views by using/reflect them.
The only way we can "temporarily" fix this is to not replace the url when reflecting new parameters to the URL from the modal. It will ensure that there is no back navigation possible. But this is clearly not the desired way we would like to manage that.
I hope my explanation is clear!
Thank you for your help!
@vincentpalita I am not exactly sure what issue you are dealing with. Is it possible to isolate the case in a sample Playground demo, so we could take a look?
I appear to have another related issue: When I try to navigate in the result chain from a modal, it undoes the navigation. e.g.:
const options: ModalDialogOptions = {
viewContainerRef: this.viewContainerRef
}
this.modalService.showModal(SomeSearcherModal, options).then(result => {
if (result) {
this.routerExt.navigate(['/somebaseroute', result.id], {clearHistory: true});
}
});
Strangely reopening the modal and trying again seems to work.
Alternatively it can be completely worked around by wrapping the navigate
line in setTimeout
:
setTimeout(() => {
this.routerExt.navigate(['/somebaseroute', result.id], {clearHistory: true});
}
tns-android: 5.4.0
"tns-core-modules": "~5.4.2",
"nativescript-angular": "~8.0.0",
"@angular/core": "8.0.0"
In my case I use a modalView to create a custom prompt dialog (with timepicker) ... because strangely, there is no customDialog functionnality in the Dialog section..
When my modal calls .closeCallback()
my main navigation is auto-redirected to home because of the internally called this.location._closeModalNavigation()
fn.. But it's a dialog, just dont do anything except returning the damn value from the prompt !
How to disable this redirect ?
edit: I am in the case "Closing a modal that was opened on a page navigated to with skipLocationChange: true, will cause a navigate to the previous page" ...
In my case I use a modalView to create a custom prompt dialog (with timepicker) ... because strangely, there is no customDialog functionnality in the Dialog section..
When my modal calls
.closeCallback()
my main navigation is auto-redirected to home because of the internally calledthis.location._closeModalNavigation()
fn.. But it's a dialog, just dont do anything except returning the damn value from the prompt !How to disable this redirect ?
edit: I am in the case "Closing a modal that was opened on a page navigated to with skipLocationChange: true, will cause a navigate to the previous page" ...
same here as @jscti said .... Need a way to avoid that damn auto redirection.... without that I'm forced to use a regular page navigation instead of a dialog which is really more convenient than a full navigation page... Is there any way of rewriting the last stacked route somehow ? I've tried CustomRouteStrategy without success...
Same for me two years later, causing many problems using modal dialogs on iOS. Simply setTimeout solves the problem if you have simple components, but in case of something more complex, you end up with multiple instances of the same component.
Does anyone know what's happening behind it and why ModalService is affecting routing?
I have a small demo app based where when opening an item from the list by:
- taping on item routes you to item details
- double tapping on an item opens a modal that redirects to item details when closed. After redirecting to item details router redirects once more to the list, which is the third route in the router stack.
Here is the repo for testing: https://github.com/brndusic/nativescript-modal-routing-problem
Same for me two years later, causing many problems using modal dialogs on iOS. Simply setTimeout solves the problem if you have simple components, but in case of something more complex, you end up with multiple instances of the same component.
Does anyone know what's happening behind it and why ModalService is affecting routing?
I have a small demo app based where when opening an item from the list by:
1. taping on item routes you to item details 2. double tapping on an item opens a modal that redirects to item details when closed. After redirecting to item details router redirects once more to the list, which is the third route in the router stack.
Here is the repo for testing: https://github.com/brndusic/nativescript-modal-routing-problem
I have same issue