【问题标题】:Angular routerLink navigating to wrong path on 'nested' pagesAngular routerLink 导航到“嵌套”页面上的错误路径
【发布时间】:2021-07-27 11:20:33
【问题描述】:

我正在 Angular 12 中构建一个基本的笔记应用程序,其中笔记存储在 Firebase 中。注释包含文本,但也可以作为更多注释的父节点,例如:

Note
Note
|- Note
  |- Note
  |- Note
    |- Note
|- Note
Note

您可以从/notes/{{note.id}} 查看笔记的子笔记列表,并在/edit/{{note.id}} 编辑笔记本身。如果/notes/ 的 id 为 null,它会抓取所有顶级注释。

问题:一切正常,直到我尝试查看层次结构第二级的笔记列表。 routerLink 似乎将/edit/{{note.id}}/notes/{{note.id}} 添加到导航堆栈,例如:

Note1
|- Note2 <-- click '>' button on note2 in list view
  |- Note3 <-- expect to see note3 in list view

我没有查看notes/2,而是转到edit/2。在浏览器中单击返回将我带到我想要的 notes/2 的正确路线,允许我在列表视图中看到 note3。为什么单击图标按钮时会在路由器中添加/edit/{{note.id}}

编辑:在这里演示问题的 StackBlitz 链接: https://stackblitz.com/edit/angular-hcmvab

相关代码sn-ps如下:

app-routing.module.ts

const routes: Routes = [
  { path: '', redirectTo: 'notes', pathMatch: 'full' },
  { path: 'login', component: LoginComponent },
  { path: 'notes',
    children: [
      { path: '', component: NotesComponent },
      { path: ':id', component: NotesComponent },
    ],
  },
  { path: 'edit/:id', component: NoteDetailsComponent }
];

notes.component.ts

export class NotesComponent implements OnInit {
  parentID = this.route.snapshot.paramMap.get('id');
  notes: any;

  constructor(
    private route: ActivatedRoute,
    private notesService: NotesService
  ) {}

  ngOnInit(): void {
    this.retrieveNotes();
  }

  retrieveNotes(): void {
    this.notesService
      .getChildNotes(this.parentID)
      .snapshotChanges()
      .pipe(
        map((changes: any) =>
          changes.map((c: any) => ({
            id: c.payload.doc.id,
            ...c.payload.doc.data(),
          }))
        )
      )
      .subscribe((data) => {
        this.notes = data;
      });
  }
}

notes.component.html

<mat-list>
  <mat-list-item *ngFor="let note of notes" [routerLink]="['/edit', note.id]">
    <mat-icon fontSet="material-icons-outlined" mat-list-icon>description_outlined</mat-icon>
    <div mat-line>{{note?.title}}</div>
    <div class="spacer"></div>
    <button mat-icon-button *ngIf="note.children.length > 0" [routerLink]="['/notes', note.id]">
      <mat-icon>arrow_forward_ios</mat-icon>
    </button>
  </mat-list-item>
</mat-list>

【问题讨论】:

    标签: angular angular-router


    【解决方案1】:

    您正在寻找的是具有可变数量参数的路线。像/note/a/b/c/d/e 这样的东西。实现这一目标的一种方法是使用带有自定义 url 匹配器的路由,如果它以 /note (或您选择的前缀)开头,则接受该路由并收集所有其余段并将它们传递给组件。

    以下是路线的定义方式:

    const variableRouteMatcher: UrlMatcher = (
      segments: UrlSegment[]
    ): UrlMatchResult => {
      if (segments.length >= 1 && segments[0].path === 'note') {
        const fullPath = segments
          .slice(1)
          .map(r => r.path)
          .join('/');
        return {
          consumed: segments,
          posParams: {
            fullPath: new UrlSegment(fullPath, {})
          }
        };
      }
      return null;
    };
    
    const routes: Routes = [
      { matcher: variableRouteMatcher, component: NoteComponent }
    ];
    

    工作StackBlitz 示例

    编辑(基于评论) 在查看了您的 stackblitz 之后,我发现了两个问题,一个正如 Cantarzo 在他的回答中指出的那样,即另一个链接元素内部有一个链接元素。

    但更严重的错误是您的notes 组件不会监听其路由参数的变化,它会获取路由的快照,然后永远使用它。请记住,Angular 在路由中重用组件,因此每当您导航到注释时,都会使用相同的 NoteComponent 实例。

    这意味着当您第一次导航到笔记时,它会获取其父 ID,然后无论您走到哪里,父 ID 都保持不变。

    要解决这个问题,您必须订阅激活路线参数的更改并相应地更新您的父 ID(以及您的子注释)

    查看您的forked stacklitz

    【讨论】:

    • 感谢您的建议和示例,但这对于我的需求来说似乎有点过头了。每个笔记都有一个唯一的 id,其内容可以通过 /edit/id 查看,任何子笔记都可以通过 /notes/id 查看,无论嵌套多深。从 Angular 文档中,指定 ['/'] 的 routerLink 应该引用我的应用程序的根 URL,但它不会在第一个孩子之后。这里有一个 StackBlitz 来突出这个问题:stackblitz.com/edit/angular-hcmvab
    • 感谢您更新您的答案 - 这为我解决了问题!没有看到我对参数进行了快照,我觉得有点愚蠢。我还将确保(根据其他答案)分开链接。谢谢!
    【解决方案2】:

    问题是你把一个[routerLink] 放在另一个里面。 您应该将[routerLink] 属性从&lt;mat-list-item&gt; 移动到另一个位置,例如其中的一个按钮。您这样做的方式可能是先激活按钮单击,然后单击整个列表项。

    试着改成这样:

         <mat-list-item *ngFor="let note of notes" >
            <mat-icon fontSet="material-icons-outlined" mat-list-icon>description_outlined</mat-icon>
            <div mat-line>{{note?.title}}</div>
            <div class="spacer"></div>
            <button mat-icon-button [routerLink]="['/notes', note.id]">
              <mat-icon>Some-Edit-Icon</mat-icon>
            </button>
            <button mat-icon-button *ngIf="note.children.length > 0" [routerLink]="['/notes', note.id]">
              <mat-icon>arrow_forward_ios</mat-icon>
            </button>
          </mat-list-item>
        </mat-list>
    

    不仅仅是调整你喜欢的方式。 您可能遇到的另一个问题是您将notes.id 传递给访问儿童笔记的[routerLink]。也许您应该输入*ngFor 并改为传递children.id

    如果此解决方案不起作用,请创建一个 stackBlitz,以便我们更清楚地看到问题。

    【讨论】:

    • 您好,感谢您的评论。我已经尝试过了,但行为仍然存在。如果有帮助,我会迅速将这个 StackBlitz 拼凑在一起:stackblitz.com/edit/angular-hcmvab。目的是让它看起来像一个带有无限嵌套笔记的移动应用程序。
    • 感谢您的帮助 - 我接受了另一个答案,因为它解决了快照参数的根本问题(没有双关语),但您拆分链接的建议也已被采纳。
    猜你喜欢
    • 2016-09-16
    • 2023-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-05
    • 2021-05-22
    • 1970-01-01
    • 2019-07-26
    相关资源
    最近更新 更多