Открыть/закрыть сиденав из другого компонента

Я использую angular (последняя версия) и angular материал.

Есть 3 компонента:

  • header.component, в котором есть кнопка управления справа-sidenav
  • rigth-sidenav.component, в котором есть право-sidenav
  • sidenav.component (это левое главное меню), этот компонент вызывает header.component, right-sidenav.component и контент

Как открыть/закрыть сиденав из другого компонента? (в моем случае кнопка находится в header.component).

Попробовал следующий вариант (но получил ошибку: TypeError: this.RightSidenavComponent.rightSidenav не определен):

header.component.html

<button mat-button (click)="toggleRightSidenav()">Toggle side nav</button>

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();
    }

}

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>

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;
    }

}

правой sidenav.component.html

<mat-sidenav #rightSidenav mode="side" opened="true" class="rightSidenav"
             [fixedInViewport]="true" [fixedTopGap]="250">
    Sidenav
</mat-sidenav>

правой 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() { }

}

Нерабочий пример с кодом stackblitz

Ответ 1

У меня была такая же проблема с использованием. Я решил это так.

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();
   }

Ваш компонент

constructor(
private sidenav: SidenavService) { }

toggleRightSidenav() {
   this.sidenav.toggle();
}

Свяжите свой HTML toggle() в соответствии с вашими требованиями.

Компонент приложения.

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

constructor(private sidenavService: SidenavService) {
}

ngOnInit(): void {
  this.sidenavService.setSidenav(this.sidenav);
}

Модуль приложения

providers: [YourServices , SidenavService],

Рабочий пример с кодом stackblitz

Ответ 2

Я использовал @Input() remoteSideNav: MatSideNav в родительском\другом компоненте для передачи объекта 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>

макета header.component.html

<section>
  <mat-toolbar>
    <span (click)="inputSideNav.toggle()">Menu</span>
  </mat-toolbar>
</section>

макета 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() {
  }
}

Ответ 3

Прежде всего, вам не нужно вызывать rightSideNav в компоненте sideNav. Ваша кнопка переключения находится в компоненте заголовка. Таким образом, вы можете сделать это в своем компоненте заголовка.

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 {
        rightSideNav : boolean ;
        constructor(public RightSidenavComponent:RightSidenavComponent) {   }


        sideNavBtnToggle(){
        if(this.rightSideNav == false)
        {
               this.rightSideNav = true;
        }
        else{
               this.rightSideNav = false;
        } 
}
}

И в вашем header.component.html

введите этот код:

<app-right-sidenav *ngIf="rightSideNav"></app-right-sidenav>

Это облегчит вашу работу.