【问题标题】:change mat-sidenav content dynamically from any component从任何组件动态更改 mat-sidenav 内容
【发布时间】:2019-11-08 09:04:48
【问题描述】:

我正在尝试根据按钮单击等操作从不同的路由组件加载 mat-sidenav 中的不同组件?

我创建了一个单例服务“SidenavService”以使用 @ViewChild 获取对 mat-sidenav 的引用,这样我就可以从应用程序的任何位置控制(如打开、关闭、切换等)sidenav。

我还在 mat-sidenav 中创建了一个 ng-container 并将其 ViewConteinerRef 存储在 SidenavService 中,现在在组件层次结构中的任何组件中,我都可以注入 SidenavService 并且可以使用 ViewConteinerRef 来创建嵌入式视图。

stackblitz 链接 https://stackblitz.com/edit/angular-material-sidenav-dynamic-content

有没有更好的方法来实现这一点?从应用程序的任何位置加载 mat-sidenav 中的不同组件。

【问题讨论】:

    标签: angular angular-material2


    【解决方案1】:

    通过您的 StackBlitz 进行实验,我提出了一个使用 Angular CDK(组件开发工具包)中的 portal component 的解决方案。

    我所做的是修改原始SidenavService 代码以允许将Portal 传递给Subject,这将向任何订阅Subject 的组件发出Portal。动态 sidenav 将在 sidenav 内部有一个 <ng-template> 部分,其中 cdkPortalOutlet 属性绑定到 Portal Subject

    <mat-sidenav #rightPanel position="end">
      <ng-template [cdkPortalOutlet]="panelService.panelPortal | async"></ng-template>
    </mat-sidenav>
    
    export class AppComponent {
      constructor(public panelService: PanelService) { }
    }
    

    但是,请务必将 PortalModule@angular/cdk/portal 入口点导入到您应用的模块中:

    import { PortalModule } from '@angular/cdk/portal';
    // ...
    
    @NgModule({
      imports: [
        // ...
        PortalModule
      ],
      // ...
    })
    

    通过允许SidenavService 代码允许Portal 引用,您现在可以将模板引用(TemplateRef&lt;T&gt;) 或组件(ComponentType&lt;T&gt;) 传递给SidenavService。这样可以简化代码,无需为 sidenav 的动态内容创建专用组件。

    但是,TemplatePortal (which is a Portal that represents an embedded template) 要求为第二个参数指定 ViewContainerRef。在这种情况下,我所做的是允许用户指定一个 ViewContainerRef 以传递给服务,以便将其用于 TemplatePortal

    无论如何,这是服务代码的一部分。 (注:我已将服务名称修改为更好听的名称:PanelService

    import { from } from 'rxjs';
    // ...
    
    export class PanelService {
      /** The panel. */
      panel: MatSidenav;
      private vcr: ViewContainerRef;
      // Note: The Portal class requires that a generic is specified for the component/template type.
      private panelPortal$ = new Subject<Portal<any>>();
    
      get panelPortal() {
        return from(this.panelPortal$); // Or this.panelPortal$.asObservable()
      }
    
      setViewContainerRef(vcr: ViewContainerRef) {
        this.vcr = vcr;
      }
    
      setPanelPortal(portal: Portal<any>) {
        this.panelPortal$.next(portal);
      }
    
      // Wrapper methods for MatSidenav go here.
      // ...
    }
    

    这里有一个StackBlitz 供你玩耍。

    希望这会有所帮助!

    【讨论】:

    • 很好的答案,谢谢。由于 flexlayout,您的 stackblitz 不起作用。 Stackbliz 现在在 ivy 上运行,显然它有问题。我刚刚删除了 flexlayout 部分,它可以工作。
    • 嘿@Laker,我已经解决了 StackBlitz 项目无法正常运行的问题。
    猜你喜欢
    • 2018-12-08
    • 2021-08-21
    • 2021-01-14
    • 2020-04-06
    • 1970-01-01
    • 2018-06-25
    • 2019-12-12
    • 2014-03-04
    • 1970-01-01
    相关资源
    最近更新 更多