如果命名路由器出口有活动路线,则隐藏元素

Hide element if named router-outlet has active route

我们目前正在开发一个 Angular 13 应用程序,该应用程序分为几个独立的模块,由不同的团队维护,每个模块代表 UI 由其自身支持的不同应用程序微服务。 允许这些模块依赖于我们的“SharedModule”,但反之则不行。

现在,我们要实现一个“帮助中心”,它由一个浮动在右下角的问号按钮组成,如果单击它,则可以为当前加载的页面提供帮助。问题是,我们希望将每个模块的帮助中心页面的内容保留在该模块内,此外,某些模块不需要帮助中心页面。

我们当前的解决方案向我们的主布局添加了一个组件:

<router-outlet name="navbar"></router-outlet>

<router-outlet></router-outlet>

<app-help></app-help>

<router-outlet name="footer"></router-outlet>

app-help组件有说浮动按钮,

<button mat-fab (click)="openHelpCenter()">
  <mat-icon>help</mat-icon>
</button>

打开一个 Material 对话框,里面有一个名为 router-outlet 的对话框:

@Component({
  selector: 'app-help',
  templateUrl: './help.component.html',
  styleUrls: ['./help.component.scss']
})
export class HelpComponent {


  constructor(
    private dialog: MatDialog,
  ) {
  }

  openHelpCenter() {
    this.dialog.open(HelpDialogComponent, {
      width: '300px'
    })
  }
}

@Component({
  selector: 'app-help-dialog',
  template: '<router-outlet name="help"></router-outlet>'
})
export class HelpDialogComponent {

  constructor() {
  }
}

在每个模块中,团队现在可以实现使用命名 router-outlet:

的路由
...
{
        path: '',
        component: HelpComponent,
        outlet: 'help'
}
...

它根据当前加载的 url.

在 Dialog 中“注入”模块 HelpComponent

这工作得很好,但是,我们有一个未解决的问题:

如果路由器出口为空,即如果您在不提供帮助的页面上,我们如何隐藏浮动按钮?

我认为最简单的解决方案(即用最少的模块内代码管理内容的解决方案)是在 HelpComponent 内监听 Router 事件,例如NavigationEnd,然后找出“帮助”-router-outlet 是否有“活动”路由,并相应地设置可见性。 (类似于 RouterLinkActive-指令)

但是,我无法找到如何从 Router-Framework 中检索此信息。

当然,我也很感激关于如何以不同方式解决问题的想法。

您可以让服务保存一个布尔值,并让模块手动打开或关闭 init 上的帮助以满足它们的需要。我们在我们的应用程序中做了类似的事情,但也订阅了基于某些路线翻转的导航事件。

您还可以在路由中添加查询参数,例如 showhelp=true 或 false,并在主要组件中对其做出反应。

你也可以在主组件中有一个白名单,你可以在其中按住帮助按钮并在此处收听路由事件,然后使用映射来控制其上的 ngif。

很多选择,不确定哪个是最好的,我很好奇你最终选择了哪条路线

阅读 Angular 路由器源代码后,我偶然发现了 ChildrenOutletContexts,它似乎是当前“活动”插座的地图。

我调整了我的组件以将其注入并在每次导航完成时检查它:

import {
  ChildrenOutletContexts,
  NavigationEnd,
  Router
} from "@angular/router";
import {filter} from "rxjs";
import {map} from "rxjs/operators";

@Component({
  selector: 'app-help',
  templateUrl: './help.component.html',
  styleUrls: ['./help.component.scss']
})
export class HelpComponent {
  helpOutletActive$ = this.router.events.pipe(
    filter(event => event instanceof NavigationEnd),
    map(() => this.contexts.getContext('help') !== null)
  )

  constructor(
    private dialog: MatDialog,
    private router: Router,
    private contexts: ChildrenOutletContexts
  ) {
  }

  openHelpCenter() {
    this.dialog.open(HelpDialogComponent, {
      width: '300px'
    })
  }
}

根据我的测试,这似乎产生了预期的结果