为什么我不能重定向到内部路由?

huangapple go评论71阅读模式
英文:

Why I can't redirect to inner route?

问题

当我点击/链接时,为什么它不会重定向到/en/dashboard?它只会重定向到/en

但是在路由器中,有一条规则说:“重定向到dashboard”:

const routes: Route[] = [
  { path: '', redirectTo: '/en', pathMatch: 'full' },
  {
    path: ':lang',
    component: ShellComponent,
    children: [
      { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, // <-- 这里是第二次重定向
      { path: 'dashboard', component: DashboardComponent },
    ],
  },
];

所以我期望它重定向到/en,然后再次重定向到dashboard,最终我会得到/en/dashboard

在Angular中如何实现这一点?

import 'zone.js/dist/zone';
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, Route, RouterModule } from '@angular/router';

@Component({
  selector: 'dashboard',
  template: `在dashboard组件中`,
  standalone: true,
})
export class DashboardComponent {}

@Component({
  selector: 'shell',
  template: `在shell组件中 <router-outlet></router-outlet>`,
  standalone: true,
  imports: [RouterModule],
})
export class ShellComponent {}

const routes: Route[] = [
  { path: '', redirectTo: '/en', pathMatch: 'full' },
  {
    path: ':lang',
    component: ShellComponent,
    children: [
      { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
      { path: 'dashboard', component: DashboardComponent },
    ],
  },
];

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule, RouterModule],
  template: `
    <h1>Hello from {{name}}!</h1>
    <a target="_blank" href="https://angular.io/start">
      了解更多关于Angular的信息
    </a>
    <br><br>
    <a [routerLink]="['/']">/</a><br>
    <a [routerLink]="['/en']">/en</a><br>
    <a [routerLink]="['/dashboard']">/dashboard</a><br>

    <router-outlet></router-outlet>
  `,
})
export class App {
  name = 'Angular';
}

bootstrapApplication(App, { providers: [provideRouter(routes)] });

stackblitz演示

英文:

Why, when I click on / link, it won't redirect me to /en/dashboard? It only redirects to /en.

But in the router, there is a rule that says "redirect to dashboard":


const routes: Route[] = [
{ path: &#39;&#39;, redirectTo: &#39;/en&#39;, pathMatch: &#39;full&#39; },
{
path: &#39;:lang&#39;,
component: ShellComponent,
children: [
{ path: &#39;&#39;, redirectTo: &#39;dashboard&#39;, pathMatch: &#39;full&#39; }, // &lt;-- here second redirect
{ path: &#39;dashboard&#39;, component: DashboardComponent },
],
},
];

So I expect it to redirect to /en then make a sub redirect to dashboard so in the end I will get /en/dashboard.

How to do that in angular?

import &#39;zone.js/dist/zone&#39;;
import { Component } from &#39;@angular/core&#39;;
import { CommonModule } from &#39;@angular/common&#39;;
import { bootstrapApplication } from &#39;@angular/platform-browser&#39;;
import { provideRouter, Route, RouterModule } from &#39;@angular/router&#39;;
@Component({
selector: &#39;dashboard&#39;,
template: `in dahsboard component`,
standalone: true,
})
export class DashboardComponent {}
@Component({
selector: &#39;shell&#39;,
template: `in shell component &lt;router-outlet&gt;&lt;/router-outlet&gt;`,
standalone: true,
imports: [RouterModule],
})
export class ShellComponent {}
const routes: Route[] = [
{ path: &#39;&#39;, redirectTo: &#39;/en&#39;, pathMatch: &#39;full&#39; },
{
path: &#39;:lang&#39;,
component: ShellComponent,
children: [
{ path: &#39;&#39;, redirectTo: &#39;dashboard&#39;, pathMatch: &#39;full&#39; },
{ path: &#39;dashboard&#39;, component: DashboardComponent },
],
},
];
@Component({
selector: &#39;my-app&#39;,
standalone: true,
imports: [CommonModule, RouterModule],
template: `
&lt;h1&gt;Hello from {{name}}!&lt;/h1&gt;
&lt;a target=&quot;_blank&quot; href=&quot;https://angular.io/start&quot;&gt;
Learn more about Angular 
&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
&lt;a [routerLink]=&quot;[&#39;/&#39;]&quot;&gt;/&lt;/a&gt;&lt;br&gt;
&lt;a [routerLink]=&quot;[&#39;/en&#39;]&quot;&gt;/en&lt;/a&gt;&lt;br&gt;
&lt;a [routerLink]=&quot;[&#39;/dashboard&#39;]&quot;&gt;/dashboard&lt;/a&gt;&lt;br&gt;
&lt;router-outlet&gt;&lt;/router-outlet&gt;
`,
})
export class App {
name = &#39;Angular&#39;;
}
bootstrapApplication(App, { providers: [provideRouter(routes)] });

stackblitz demo

答案1

得分: 1

以下是翻译好的部分:

你在期望点击"/"链接时会重定向到"/en/dashboard"是正确的。你的路由配置是正确的。

问题可能不在于路由配置,而可能是由于Angular Router的生命周期引起的。当Angular Router重定向到新路径时,它首先会停用先前路由的组件,然后激活新路由的组件。

然而,如果先前和新的路由共享相同的组件(如"/"和"/en"的情况),Angular Router 将不会停用和重新激活组件,因此不会重新评估重定向。

要解决这个问题,你可以在路由模块中使用onSameUrlNavigation配置选项。这个选项配置了当路由器接收到对当前URL的导航请求时应该如何行为。

以下是如何修改你的路由模块配置的示例:

@NgModule({
  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})],
  exports: [RouterModule]
})
export class AppRoutingModule { }

在这个配置中,onSameUrlNavigation: 'reload' 告诉Angular Router每次检测到对当前URL的导航时都重新处理路由管道。

请在应用程序应用此更改后检查,并告诉我问题是否已解决。

希望这个答案对你有帮助。

======= 答复 Jon Sud =======

问题可能与子路由定义中redirectTo的使用方式有关。在Angular文档中提到:

redirectTo属性指定了重定向目标的相对路径。

在你的情况下,父路由是动态的:lang,当你尝试使用redirectTo: 'dashboard'时,它可能无法正确解析路由,因为它是相对于父路由的。

一个可能的解决方案是在redirectTo中使用绝对路径。以下是如何调整你的路由的示例:

const routes: Route[] = [
  { path: '', redirectTo: '/en', pathMatch: 'full' },
  {
    path: ':lang',
    component: ShellComponent,
    children: [
      { path: '', redirectTo: '/en/dashboard', pathMatch: 'full' },
      { path: 'dashboard', component: DashboardComponent },
    ],
  },
];

虽然这不是一个动态的解决方案(它总是重定向到'/en/dashboard'),但基于你当前的设置,它应该可以工作。要使其更加动态,你可能需要创建一个守卫或解析器来处理基于动态的:lang参数的重定向。

另一种解决方案可能是避免嵌套的重定向,并在顶层处理重定向:

const routes: Route[] = [
  { path: '', redirectTo: '/en/dashboard', pathMatch: 'full' },
  {
    path: ':lang',
    component: ShellComponent,
    children: [
      { path: 'dashboard', component: DashboardComponent },
    ],
  },
];

在这种情况下,对基本URL的任何请求都将直接重定向到'/en/dashboard'。

请尝试这些解决方案,并告诉我它们是否适用于你。

英文:

You are correct in expecting that clicking on the "/" link should redirect you to "/en/dashboard". The routes configuration you have is correct.

The problem might not be with the routes configuration, but it could be due to the Angular Router's lifecycle. When Angular Router redirects to a new path, it first deactivates the components from the previous route, then activates the components for the new route.

However, if the previous and new routes share the same components (as is the case with "/" and "/en"), Angular Router will not deactivate and re-activate the components, and thus will not re-evaluate the redirect.

To solve this issue, you can use the onSameUrlNavigation configuration option in the router module. This option configures how the router should behave if it receives a navigation request to the current URL.

Here is how you can modify your router module configuration:

@NgModule({
  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: &#39;reload&#39;})],
  exports: [RouterModule]
})
export class AppRoutingModule { }

In this configuration, onSameUrlNavigation: 'reload' tells Angular Router to reprocess the routing pipeline every time it detects navigation to the current URL.

Please check your application after applying this change and let me know if the issue is resolved.

Hope this answer would be helpful.

====== Reply to Jon Sud =====

It's possible that the issue is related to the way redirectTo is used in the child route definition. In the Angular documentation, it's mentioned that:

The redirectTo property of the definition specifies the relative path of a redirection target.

In your case, the parent route is dynamic :lang, and when you try to use redirectTo: 'dashboard', it may not correctly resolve the route as it's relative to the parent.

One possible solution is to use an absolute path in the redirectTo. Here's how you could adjust your routes:

const routes: Route[] = [
  { path: &#39;&#39;, redirectTo: &#39;/en&#39;, pathMatch: &#39;full&#39; },
  {
    path: &#39;:lang&#39;,
    component: ShellComponent,
    children: [
      { path: &#39;&#39;, redirectTo: &#39;/en/dashboard&#39;, pathMatch: &#39;full&#39; },
      { path: &#39;dashboard&#39;, component: DashboardComponent },
    ],
  },
];

While this isn't a dynamic solution (it always redirects to '/en/dashboard'), it should work based on your current setup. To make it more dynamic, you may need to create a guard or a resolver to handle the redirection based on the dynamic :lang parameter.

Another solution could be to avoid the nested redirect and handle the redirect at the top level:

const routes: Route[] = [
  { path: &#39;&#39;, redirectTo: &#39;/en/dashboard&#39;, pathMatch: &#39;full&#39; },
  {
    path: &#39;:lang&#39;,
    component: ShellComponent,
    children: [
      { path: &#39;dashboard&#39;, component: DashboardComponent },
    ],
  },
];

In this case, any request to the base URL will be redirected to '/en/dashboard' directly.

Please try these solutions and let me know if they work for you.

答案2

得分: 0

维克多·萨夫金是Angular路由器的核心创作者之一,这是他的书《Angular路由器》中的一部分:

路由器强加的一个约束是在配置的任何级别上,路由器只应用一个重定向,即不能链接重定向。

这本书中的示例与您的情况完全相同。因此,您不能同时使用多个重定向。

英文:

Victor Savkin one of core creators of Angular Router, and this is from his book named "Angular Router":

> One constraint the router imposes is at any level of the configuration
> the router applies only one redirect, i.e., redirects cannot be
> chained.

And the example in this book exactly as yours. So you can't use multiple redirects at once.

huangapple
  • 本文由 发表于 2023年7月23日 19:11:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76747928.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定