Access Parent @Component and vars from *Routed* Ch

2019-04-20 19:57发布

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().

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:

<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?

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:

// 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??

2条回答
你好瞎i
2楼-- · 2019-04-20 20:14

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).

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:

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.

查看更多
【Aperson】
3楼-- · 2019-04-20 20:33

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:

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>
查看更多
登录 后发表回答