从* Routed * Child Component访问Parent @Component和vars

时间:2021-09-07 13:02:25

I am trying to toggle a side nav menu, located at the top of my main App template using a button in a nested child component. I can't figure out how to get to the sidenav component in the parent to tell it to sidenav.open().

我正在尝试使用嵌套子组件中的按钮切换位于主App模板顶部的侧面导航菜单。我无法弄清楚如何到达父节点中的sidenav组件来告诉sidenav.open()。

I know about @Input and @Output on a child component, but as I understand it, to use this I need to have some sort of DOM tag for the child component to attach these to? Such as:

我知道关于子组件的@Input和@Output,但据我所知,要使用它,我需要为子组件添加某种DOM标记来附加它们吗?如:

<app>
  <sidenav-component #sidenav>...</sidenav-component>

  <child [someInput]="some_parent_var" (childOpensNav)="sidenav.open()"></child>
</app>

Tons of articles on how to do this. Problem is that I'm routing to this component so no <child> tag exists explicitly in the code. Rather my code is like this:

关于如何做到这一点的文章很多。问题是我正在路由到此组件,因此代码中没有显式存在 标记。相反,我的代码是这样的:

<app>
  <sidenav-component #sidenav>...</sidenav-component>

  <router-outlet></router-outlet>
</app>

If I have a child component that gets routed to, how do I do a sidenav.open() or somehow access a component in the parent from the child?

如果我有一个路由到的子组件,我该如何进行sidenav.open()或以某种方式访问​​子组件中父组件?

Some thoughts: I've done some research and thinking about a couple of approaches and not sure if they are correct or would even work...One approach being using the Injector service and trying to traverse up to the parent, but this feels wrong:

一些想法:我已经做了一些研究并思考了几种方法,并且不确定它们是否正确或甚至可以工作......一种方法是使用Injector服务并尝试遍历父母,但这感觉不对:

// child component
constructor(injector: Injector) {
  this.something = injector.parent.get(Something);
}

Or possibly creating a Service in the parent, somehow attached to the Sidenav component and then injecting this service into the child??

或者可能在父级中创建服务,以某种方式附加到Sidenav组件,然后将此服务注入到子级中?

2 个解决方案

#1


9  

The easiest and cleanest way is indeed to leverage a service.

确保最简单,最干净的方法是利用服务。

The service how it could look like:

该服务的外观如下:

export class DomService {
    sidebarVisible: boolean = true;

    showSidebar() {
        sidebarVisible = true;
    }

    hideSidebar() {
        sidebarVisible = false;
    }

    toggleSidebar() {
        sidebarVisible = !sidebarVisible;
    }
}

In your bootstrap call add the service to the list of providers:

在引导程序调用中,将服务添加到提供程序列表中:

bootstrap(App, [
    // other providers
    DomService
]);

In the components (maybe in app.ts but also in your sidenav.ts) where you want to show/hide the sidebar add the service for injection:

在组件中(可能在app.ts中,也可以在sidenav.ts中),您要显示/隐藏侧栏,添加注入服务:

constructor(private _domService: DomService) {

}

In your template, where you want to toggle/show/hide you can do now:

在您希望切换/显示/隐藏的模板中,您现在可以执行以下操作:

<sidenav-component *ngIf="_domService.sidebarVisible">...</sidenav-component>

<div id="toggle-sidebar" (click)="_domService.toggleSidebar()">toggle</div>

#2


0  

I like the accepted answer, seems a more robust Angular way to do it properly (especially if you are going to be adding more options).

我喜欢接受的答案,似乎是一种更健壮的Angular方式来正确地完成它(特别是如果你要添加更多选项)。

However, I wanted quick dirty access to a global element by Id. Everybody talks about using @ViewChild but I want to walk UP the tree. I just went back to school and used this in the component method:

但是,我想通过Id快速访问全局元素。每个人都在谈论使用@ViewChild,但我想走上树。我刚回到学校并在组件方法中使用它:

document.getElementById('nav-panel').className = 'hide';

If we want multiple copies of this to work (e.g. left and right side menus) we need to inject something down the children so they know which Id to look for.

如果我们想要多个副本工作(例如左侧和右侧菜单),我们需要向孩子们注入一些内容,以便他们知道要查找哪个ID。

#1


9  

The easiest and cleanest way is indeed to leverage a service.

确保最简单,最干净的方法是利用服务。

The service how it could look like:

该服务的外观如下:

export class DomService {
    sidebarVisible: boolean = true;

    showSidebar() {
        sidebarVisible = true;
    }

    hideSidebar() {
        sidebarVisible = false;
    }

    toggleSidebar() {
        sidebarVisible = !sidebarVisible;
    }
}

In your bootstrap call add the service to the list of providers:

在引导程序调用中,将服务添加到提供程序列表中:

bootstrap(App, [
    // other providers
    DomService
]);

In the components (maybe in app.ts but also in your sidenav.ts) where you want to show/hide the sidebar add the service for injection:

在组件中(可能在app.ts中,也可以在sidenav.ts中),您要显示/隐藏侧栏,添加注入服务:

constructor(private _domService: DomService) {

}

In your template, where you want to toggle/show/hide you can do now:

在您希望切换/显示/隐藏的模板中,您现在可以执行以下操作:

<sidenav-component *ngIf="_domService.sidebarVisible">...</sidenav-component>

<div id="toggle-sidebar" (click)="_domService.toggleSidebar()">toggle</div>

#2


0  

I like the accepted answer, seems a more robust Angular way to do it properly (especially if you are going to be adding more options).

我喜欢接受的答案,似乎是一种更健壮的Angular方式来正确地完成它(特别是如果你要添加更多选项)。

However, I wanted quick dirty access to a global element by Id. Everybody talks about using @ViewChild but I want to walk UP the tree. I just went back to school and used this in the component method:

但是,我想通过Id快速访问全局元素。每个人都在谈论使用@ViewChild,但我想走上树。我刚回到学校并在组件方法中使用它:

document.getElementById('nav-panel').className = 'hide';

If we want multiple copies of this to work (e.g. left and right side menus) we need to inject something down the children so they know which Id to look for.

如果我们想要多个副本工作(例如左侧和右侧菜单),我们需要向孩子们注入一些内容,以便他们知道要查找哪个ID。