Angular2 this.router.navigate fires only once

2019-05-30 07:58发布

问题:

I have the following tab structure in my page, with it's respective URLs given in braces:

           Main Tab (/page)
           /    |    \
          /     |     \
         /      |      \
        /       |       \
Sub Tab 1   Sub Tab 2   Sub Tab 3
(/page/a)   (/page/b)   (/page/c)

Component

@Input() route: string = '';

selectTab(tab) {
  let route = this.router.url.split('?')[0];

  /* Here redirectUrl = "/page/c" */
  if (tab.redirectUrl.length > 0) {
    // console.log(tab.redirectUr); gives /page/c

    this.router.navigate([tab.redirectUrl]);
    // This works but reloads the page and is a very bad idea.
    // window.location.href = tab.redirectUrl;
  }
}

Component.html

NOTE: The actual code has a custom element, I'm showing it as a <div> just to show how redirectUrl is passed.

<div route="/page" [redirectUrl]="/page/c"></div>

The selectTab function is called when I click Main Tab. And since the Main Tab has redirectUrl the if condition satisfies and the page goes from /page to /page/c. (This only works once)

But, if I click any other Sub Tab (say Sub Tab 2 with URL /page/b), then clicking on main tab doesn't redirect to /page/c, instead stays at /page/b.

I have already checked the redirectUrl inside if condition, it's still /page/c, but redirection doesn't happen.

What should I do to force redirection?

EDIT

@HuseinRoncevic

<div *ngFor="let tab of tabs" (click)="selectTab(tab)">

EDIT

Routes

{
  path: 'page',
  component: MyComponent
},
{
  path: 'page/:action',
  component: MyComponent
}

回答1:

I am not sure why your route definition points to the same component:

{
    path: 'page',
    component: MyComponent
},
{
    path: 'page/:action',
    component: MyComponent
}

Why don't you create a separate component for page/:action route?

Here is something from the Routing and Navigation documentation on Angular.io.

Observable paramMap and component reuse In this example, you retrieve the route parameter map from an Observable. That implies that the route parameter map can change during the lifetime of this component.

They might. By default, the router re-uses a component instance when it re-navigates to the same component type without visiting a different component first. The route parameters could change each time.

I believe that this is your issue. You are not really changing the components. Rather, you are reusing the same component over and over again. And for that reason router is reusing the same component instance.

For that reason I would create a new component that handles the :action part of your route.

{
    path: 'page',
    component: MyComponent
},
{
    path: 'page/:action',
    component: IHandleActionPartHereComponent
}

Update

In your selectTab() function, what is the purpose of splitting along the question mark?

let route = this.router.url.split('?')[0];

Your route will not be appended as a query parameter, but rather it will be appended to the actual route as in http://something/page/a not http://something/?page/b or however you imagined this. The url property will return the url as determined by the router: /page/a or /page/b. The length of your result should be 0. Because of that your if part will always be false and no redirection will occur.



回答2:

You can try this:

{ path: 'page', component: PageParentComponent,
        children: [
          { path: '', redirectTo: 'a', pathMatch: 'full'},
          { path: 'a', component: AComponent},
          { path: 'b', component: BComponent}
        ]
 }

in HTML

this.router.navigate(['page/a']); // or
this.router.navigate(['page/b']);