Angular - 从另一个组件打开/关闭sidenav

Den*_*nis 23 typescript angular-material angular

我使用角度(最新版本)和角度材料.

有3个组成部分:

  • header.component,其中有一个右侧的控制按钮
  • rigth-sidenav.component,其中是right-sidenav
  • sidenav.component(这是左侧主菜单),这个组件调用header.component,right-sidenav.component和content

我第一次使用Angular,请告诉我,如何从另一个组件打开/关闭sidenav(在我的例子中,按钮在header.component中).

尝试了以下选项(但得到错误:TypeError:this.RightSidenavComponent.rightSidenav未定义):

header.component.html

<button mat-button (click)="toggleRightSidenav()">Toggle side nav</button>
Run Code Online (Sandbox Code Playgroud)

header.component.ts

import { Component } from '@angular/core';
import { RightSidenavComponent } from '../right-sidenav/right-sidenav.component';
@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss']
})
export class HeaderComponent {

    constructor(public RightSidenavComponent:RightSidenavComponent) {   }
    toggleRightSidenav() {
        this.RightSidenavComponent.rightSidenav.toggle();
    }

}
Run Code Online (Sandbox Code Playgroud)

sidenav.component.html

<mat-sidenav-container class="sidenav-container">
    <mat-sidenav #sidenav mode="side" opened="true" class="sidenav"
                 [fixedInViewport]="true"> Sidenav  </mat-sidenav>
    <mat-sidenav-content>
        <app-header></app-header>
        <router-outlet></router-outlet>
        <app-right-sidenav #rSidenav></app-right-sidenav>
    </mat-sidenav-content>
</mat-sidenav-container>
Run Code Online (Sandbox Code Playgroud)

sidenav.component.ts

import { Component, Directive, ViewChild } from '@angular/core';
import { RightSidenavComponent } from '../right-sidenav/right-sidenav.component';

@Component({
  selector: 'app-sidenav',
  templateUrl: './sidenav.component.html',
  styleUrls: ['./sidenav.component.scss']
})

export class SidenavComponent {

    @ViewChild('rSidenav') public rSidenav;
    constructor(public RightSidenavComponent: RightSidenavComponent) {
        this.RightSidenavComponent.rightSidenav = this.rSidenav;
    }

}
Run Code Online (Sandbox Code Playgroud)

右sidenav.component.html

<mat-sidenav #rightSidenav mode="side" opened="true" class="rightSidenav"
             [fixedInViewport]="true" [fixedTopGap]="250">
    Sidenav
</mat-sidenav>
Run Code Online (Sandbox Code Playgroud)

右sidenav.component.ts

import { Component, Injectable } from '@angular/core';

@Component({
  selector: 'app-right-sidenav',
  templateUrl: './right-sidenav.component.html',
  styleUrls: ['./right-sidenav.component.scss']
})

@Injectable()
export class RightSidenavComponent {

    public rightSidenav: any;

    constructor() { }

}
Run Code Online (Sandbox Code Playgroud)

代码为stackblitz的非工作样本

Eld*_*dho 49

我有同样的问题使用.我这样解决了.

SidenavService

import { Injectable } from '@angular/core';
import { MatSidenav } from '@angular/material';

@Injectable()
export class SidenavService {
    private sidenav: MatSidenav;


    public setSidenav(sidenav: MatSidenav) {
        this.sidenav = sidenav;
    }

    public open() {
        return this.sidenav.open();
    }


    public close() {
        return this.sidenav.close();
    }

    public toggle(): void {
    this.sidenav.toggle();
   }
Run Code Online (Sandbox Code Playgroud)

你的组件

constructor(
private sidenav: SidenavService) { }

toggleRightSidenav() {
   this.sidenav.toggle();
}
Run Code Online (Sandbox Code Playgroud)

根据您的要求绑定您的html toggle().

应用组件.

@ViewChild('sidenav') public sidenav: MatSidenav;

constructor(private sidenavService: SidenavService) {
}

ngOnInit(): void {
  this.sidenavService.setSidenav(this.sidenav);
}
Run Code Online (Sandbox Code Playgroud)

应用模块

providers: [YourServices , SidenavService],
Run Code Online (Sandbox Code Playgroud)

使用代码stackblitz的工作示例

  • 您可以在这里https://stackblitz.com/创建一个项目吗?所以我可以通过编辑为您提供帮助吗 (2认同)
  • 唯一想到的是使用 `ngAfterViewInit()` 而不是 `ngOnInit()` - 从这篇文章 https://blog.angular-university.io/angular-viewchild/ 初始化 viewChild 确保“注入的引用@ViewChild 存在”。 (2认同)
  • 正如 @NathanBeck 提到的,如果你得到“thissidenav 未定义”,请尝试使用 ngAfterViewInit 而不是 ngOnInit。这对我有用。 (2认同)

Ash*_*sam 7

@Input() remoteSideNav: MatSideNav在parent \另一个组件中使用过,将sideNav对象作为子组件的目标属性传递。它按预期工作。顺便说一句,我喜欢@Eldho的服务实现:)

Child.component.html

<app-layout-header [inputSideNav]="sideNav"></app-layout-header>
<mat-sidenav-container>
  <mat-sidenav #sideNav (click)="sideNav.toggle()" mode="side">
    <a routerLink="/">List Products</a>
  </mat-sidenav>
  <mat-sidenav-content>
    <router-outlet></router-outlet>
  </mat-sidenav-content>
</mat-sidenav-container>
Run Code Online (Sandbox Code Playgroud)

layout-header.component.html

<section>
  <mat-toolbar>
    <span (click)="inputSideNav.toggle()">Menu</span>
  </mat-toolbar>
</section>
Run Code Online (Sandbox Code Playgroud)

layout-header.component.ts

import { Component, OnInit, Input } from '@angular/core';
import { MatSidenav } from '@angular/material';

@Component({
  selector: 'app-layout-header',
  templateUrl: './layout-header.component.html',
  styleUrls: ['./layout-header.component.css']
})
export class LayoutHeaderComponent implements OnInit {
  @Input() inputSideNav: MatSidenav;

  constructor() { }

  ngOnInit() {
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这个解决方案更简单 (3认同)

小智 7

如果您在 Angular 9+ 中工作,请记住static: true在 in 中添加参数,@ViewChild例如:

@ViewChild('rightSidenav', {static: true}) sidenav: MatSidenav;

您可以在此处查看我在 Angular 9 上运行的代码:

https://stackblitz.com/edit/angular-kwfinn-matsidenav-angular9


小智 6

为了更简单的解决方案,只需使用 @ouput() 事件发射器。

在你的父组件中

 <mat-sidenav
    #sidenav
    class="sidenav"
    fixedInViewport
    [opened]="opened"
    [mode]="mode"
  >
// catch the emitted output from child component 
<childcomponent (sidenav)="sidenav.toggle()"></childcomponent>
....
</mat-sidenav>
Run Code Online (Sandbox Code Playgroud)

子组件

<mat-toolbar>
 <div>
  <button mat-button (click)="toggle()">
   <mat-icon>menu</mat-icon>
  </button>
 </div>
</mat-toolbar>
Run Code Online (Sandbox Code Playgroud)

子组件.ts

import {Component, EventEmitter, Output} from '@angular/core';

@Component({
  selector: 'childcomponent',
  templateUrl: './childcomponent.component.html',
  styleUrls: ['./childcomponent.component.scss'],
})
export class ChildComponent {
 @Output() sidenav: EventEmitter<any> = new EventEmitter();

toggle() {
 this.sidenav.emit();
 }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个优雅而简单的解决方案。谢谢 ;) (2认同)