NativeScript / nativescript-angular

Integrating NativeScript with Angular
http://docs.nativescript.org/angular/tutorial/ng-chapter-0
Apache License 2.0
1.22k stars 241 forks source link

Android - Back navigation breaks with nested page-router-outlets. #1776

Open sbknick opened 5 years ago

sbknick commented 5 years ago

Environment Provide version numbers for the following components (information can be retrieved by running tns info in your project folder or by inspecting the package.json of the project):

Describe the bug On Android, navigation history is broken when navigating backward via nested page-router-outlets. Note: This works as expected on iOS just fine.

To Reproduce

  1. Create a NS Angular project with routes like so...
    { path: "", redirectTo: "/home/(homeoutlet:lounge)", pathMatch: "full" },
    { path: "home", component: HomeComponent, children: [
    { path: "lounge", component: LoungeComponent, outlet: "homeoutlet" },
    { path: "garage", component: GarageComponent, outlet: "homeoutlet" }
    ] },
    { path: "work", component: WorkComponent }
  2. On the Lounge page, add a button to navigate to "/home/(homeoutlet:garage)"
  3. On the Garage page, add buttons to navigate "routerExtensions.back()" and to "/work".
  4. On the Work page, add a button to navigate "routerExtendsion.back()".
  5. Run the app.
  6. Starting at Home/Lounge, navigate to Home/Garage then to Work. Then go back() and attempt to go back() again.
  7. The page will remain on the Home/Garage page despite that not being the start of the nav stack.

Expected behavior If I navigate from home/lounge -> home/garage -> work, then i press back() twice, I should return to home/lounge.

Sample project https://github.com/sbknick/ns-android-nested-back-nav

Additional context On iOS, this functions as expected.

tsonevn commented 5 years ago

HI @sbknick, Thank you for the provided sample project. I was able to recreate the issue on my side and I will log it as a bug, which we will investigate further. As a temporary solution. You can replace the router-outlet with page-router-outlet.

sbknick commented 5 years ago

Ahh, my apologies, I meant to commit <page-router-outlet> not <router-outlet>, the bug occurs using either. The same when using .back() and .backToPreviousPage() for either.

redmagic commented 5 years ago

I have a similar issue and the router.navigate Promise resolves on the second try with the value null. Maybe that's a bit of extra information.

adobrasinovic commented 5 years ago

I'm having exactly the same issue, are there possible workarounds?

farismohammed commented 5 years ago

I'm also struggling with this issue. any solution for this issue?

Eonfuzz commented 5 years ago

I am also running into this issue. Guess there's been no progress?

GrEg00z commented 5 years ago

I found a kind of workaround, by forcing the back event on homeoutlet, when the back button leads to one of children page of HomeComponent.

Considering than /home/(homeoutlet:lounge) is the starting page, I simply added in ngOnInit method in HomeComponent :

application.android.off(application.AndroidApplication.activityBackPressedEvent);
application.android.on(application.AndroidApplication.activityBackPressedEvent, (args : application.AndroidActivityBackPressedEventData) => {
       if(this.routerExtensions.router.url.indexOf("/home/(homeoutlet:") != -1 && this.routerExtensions.router.url.indexOf("/home/(homeoutlet:lounge") == -1) {
            args.cancel = true;
            this.routerExtensions.back({ relativeTo: this.activeRoute, outlets: ['homeoutlet'] });
       }
})

That was enough for me to have the behaviour expected

Impact on this workaround: if you use a modal page in one of a children page of HomeComponent, then the back button will not close the modal

tgpetrov commented 5 years ago

@sbknick

The behavior you observe is expected. Calling routerExtensions.back(); or routerExtensions.backToPreviousPage(); navigates back on the last navigated outlet.

When you navigate from lounge to garage, you navigate inside the homeoutlet, back at this point means going back in the homeoutlet, so you can successfully go back to lounge.

When you navigate to work, this is effectively navigation from home to work which happens inside the primary outlet, back at this point means going back in the primary outlet to home (which remembered its state so the homeoutlet is still on garage). Going back again is an attempt to navigate back in the primary outlet which is not possible as there is no route before home. In order to perform the navigation inside the homeoutlet, you can call routerExtensions.back({ relativeTo: this.route; });, where route is the ActivatedRoute service injected through the component’s constructor:

export class GarageComponent {
    constructor(
        private route: ActivatedRoute,
        private routerExtensions: RouterExtensions
    ) {
        console.log("garage loaded");
    }

    goBack() {
        // Don't navigate to previous page:
        // this.routerExtensions.backToPreviousPage();
        // Navigate relative to the activated route instead:
        this.routerExtensions.back({ relativeTo: this.route });
    }
    goToWork() {
        this.routerExtensions.navigate(["work"]);
    }
}

Nested navigation is thoroughly explained in this excellent article by Alexander Djenkov.

itsmerockingagain commented 3 years ago

Hi Team ,

Any fix available for this issue?

tujlaky commented 3 years ago

So basically it is not possible to have a tab navigation with pages which are not part of the tab system without hacks. I think this should be better communicated in the documentation.

Is there any plan for a better support for back navigation between different outlets?