Open/Close sidenav from another component

后端 未结 6 951
误落风尘
误落风尘 2020-12-02 12:26

I use angular (latest version) and angular material.

There are 3 components:

  • header.component, in which there is a control button for right-sidenav
相关标签:
6条回答
  • 2020-12-02 12:48

    Though people above has already answered, but I believe my solution is more simple when I solved for myself.

    You need to have a service in middle to support both components.

    Let's say, such service is NavService, below code goes into NavService:

    public toggleNav: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
    
      public toggle(): void {
        this.toggleNav.next(!this.toggleNav.value);
      }
    

    Then you have a component from where you would like to open or close your SideNav. In my case, I created the button in the Navbar as:

    button *ngIf="this.loginService.tokenSubject.value"  mat-mini-fab color="warn" (click)="onToggle()"><mat-icon>menu</mat-icon></button>
    

    Then in the SideNavComponent that you would have created for SideNav, put this in the mat-sidenav tag:

    [opened]="this.sideNavService.toggleNav.value"
    

    Of course, I injected the NavService as sideNavService in the constructor of this component.

    0 讨论(0)
  • 2020-12-02 12:49

    First of all, you don't need to toggle the right sidenav in the sidenav component. Your toggle button is in the header component, so you can do this in your header component.

    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) { }
    
      toggleRightSidenav() {
        this.rightSidenav = !this.rightSidenav;
      }
    }
    

    And in your header.component.html, use this code:

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

    This will make your work easy.

    0 讨论(0)
  • 2020-12-02 12:50

    I had the same problem using. I resolved it like this.

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

    Your Component

    constructor(
    private sidenav: SidenavService) { }
    
    toggleRightSidenav() {
       this.sidenav.toggle();
    }
    

    Bind your html toggle() based on your requirement.

    App component.

    @ViewChild('sidenav') public sidenav: MatSidenav;
    
    constructor(private sidenavService: SidenavService) {
    }
    
    ngAfterViewInit(): void {
      this.sidenavService.setSidenav(this.sidenav);
    }
    

    App Module

    providers: [YourServices , SidenavService],
    

    Working sample with code stackblitz

    Angular 9+ Update

    Per this answer on SO, "Components can no longer be imported through @angular/material. Use the individual secondary entry-points, such as @angular/material/button." As such, make sure to import MatSidenav like so:

    import { MatSidenav } from '@angular/material/sidenav';
    
    0 讨论(0)
  • 2020-12-02 12:52

    If you are working in Angular 9+ Remember add param of static: true in @ViewChild like:

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

    You can see my code working on Angular 9 here:

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

    0 讨论(0)
  • 2020-12-02 13:03

    I used @Input() inputSideNav: MatSideNav in parent\ another component to pass the sideNav object as target property from child component. It works as expected. By the way, I liked the service implementation by @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>
    

    layout-header.component.html

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

    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() {
      }
    }
    
    0 讨论(0)
  • 2020-12-02 13:04

    Just to add to Eldho's answer, you can disable animations for a true hiding effect.

        <mat-sidenav #leftbar opened mode="side" class="ng-sidenav" [@.disabled]="true">
    
    0 讨论(0)
提交回复
热议问题