从任何组件动态更改 mat-sidenav 内容
Posted
技术标签:
【中文标题】从任何组件动态更改 mat-sidenav 内容【英文标题】:change mat-sidenav content dynamically from any component 【发布时间】: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 中的不同组件。
【问题讨论】:
【参考方案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<T>
) 或组件(ComponentType<T>
) 传递给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 项目无法正常运行的问题。以上是关于从任何组件动态更改 mat-sidenav 内容的主要内容,如果未能解决你的问题,请参考以下文章
无法从 Angular 的 mat-sidenav 内的组件中检索路由参数
如何固定 mat-toolbar 和 mat-sidenav 并且在 mat-sidenav-content 内只有一个滚动条?
jQuery动态更改引导折叠组件内的progress-bar“aria-valuenow”属性和CSS“width”属性的值