我正在尝试使用嵌套子组件中的按钮切换位于主App模板顶部的侧面导航菜单。我无法弄清楚如何到达父级中的sidenav组件来告诉它sidenav.open()
。
我知道子组件上的@Input和@Output,但据我所知,要使用它,我需要为子组件添加某种DOM标记来附加它们吗?如:
<app>
<sidenav-component #sidenav>...</sidenav-component>
<child [someInput]="some_parent_var" (childOpensNav)="sidenav.open()"></child>
</app>
关于如何做到这一点的大量文章。问题是我路由到此组件,因此代码中没有明确存在<child>
标记。相反,我的代码是这样的:
<app>
<sidenav-component #sidenav>...</sidenav-component>
<router-outlet></router-outlet>
</app>
如果我有一个被路由到的子组件,我该怎样做sidenav.open()
或以某种方式访问子组件中的组件?
一些想法:我做了一些研究并思考了几种方法,并且不确定它们是否正确或甚至可以正常工作......一种方法是使用Injector服务并尝试遍历父母,但这感觉不对:
// child component
constructor(injector: Injector) {
this.something = injector.parent.get(Something);
}
或者可能在父级中创建服务,以某种方式附加到Sidenav组件,然后将此服务注入到子级中?
答案 0 :(得分:9)
最简单,最干净的方法确实是利用服务。
服务的外观:
export class DomService {
sidebarVisible: boolean = true;
showSidebar() {
sidebarVisible = true;
}
hideSidebar() {
sidebarVisible = false;
}
toggleSidebar() {
sidebarVisible = !sidebarVisible;
}
}
在bootstrap
来电中,将服务添加到提供商列表中:
bootstrap(App, [
// other providers
DomService
]);
在您希望显示/隐藏侧栏的组件(可能在app.ts
中,也可能在sidenav.ts
中)中添加注射服务:
constructor(private _domService: DomService) {
}
在您希望切换/显示/隐藏的模板中,您现在可以执行此操作:
<sidenav-component *ngIf="_domService.sidebarVisible">...</sidenav-component>
<div id="toggle-sidebar" (click)="_domService.toggleSidebar()">toggle</div>
答案 1 :(得分:0)
我喜欢接受的答案,似乎是一种更健壮的Angular方法(特别是如果你要添加更多选项)。
但是,我想通过Id快速访问全局元素。每个人都在谈论使用@ViewChild,但我想走上树。我刚回到学校并在组件方法中使用它:
document.getElementById('nav-panel').className = 'hide';
如果我们想要多个副本工作(例如左侧和右侧菜单),我们需要向孩子注入一些内容,以便他们知道要查找哪个ID。