如何通过单击具有RouterLink指令的元素来关闭Material SideNav?

时间:2017-10-25 14:56:41

标签: angular angular-material2

我将angular 4angular material结合使用。

我正在使用sidenav容器,路由器和自定义生成的菜单:

<mat-sidenav-container>
<mat-sidenav #sidenav>
    <app-menu></app-menu>
</mat-sidenav>
<router-outlet></router-outlet>
</mat-sidenav-container>

在菜单组件中我使用默认的angular 4路由器链接:

<ul>
  <li *ngFor="let hero of heroes">
    <a mat-button [routerLink]="['/hero/', hero.id]" queryParamsHandling="merge">
      {{hero.name}}
    </a>
  </li>
</ul>

我想要点击其中一个路由器链接时关闭Material sidenav

我可以向您保证,如果没有点击事件路由工作正常,它就不会关闭我的sidenav,因为路由器插座位于侧面导航内。

但是,当我向(click)="sidenav.close()"添加a时,我的整页突然刷新,而不是仅仅关注路由器链接。

我尝试了很多东西,但我似乎无法弄明白,希望有人可以提供帮助!

7 个答案:

答案 0 :(得分:17)

这是基于Angular Material的原理图生成的sidenav布局组件的完整解决方案。通过考虑我们是否在手持设备上,并确保sidenav仅在手持设备上关闭,此答案在以前的答案上得到了改进。

几点:

  1. 该组件是使用Angular Materials navigation schematics生成的。
  2. 我将组件称为my-menu,但是您也可以使用其他任何名称。
  3. 仅当我们不在手机设备上时,sidenav才会关闭,这是通过使用rxjs运算符withLatestFromisHandset$流结合而完成的是由原理图生成的。
import { Component, ViewChild } from '@angular/core';
import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { map, filter, withLatestFrom } from 'rxjs/operators';
import { Router, NavigationEnd } from '@angular/router';
import { MatSidenav } from '@angular/material';

@Component({
  selector: 'app-my-menu',
  templateUrl: './my-menu.component.html',
  styleUrls: ['./my-menu.component.css']
})
export class MyMenuComponent {
  @ViewChild('drawer') drawer: MatSidenav;

  isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
    .pipe(
      map(result => result.matches)
    );

  constructor(private breakpointObserver: BreakpointObserver,
    router: Router) {
    router.events.pipe(
      withLatestFrom(this.isHandset$),
      filter(([a, b]) => b && a instanceof NavigationEnd)
    ).subscribe(_ => this.drawer.close());
  }
}

答案 1 :(得分:4)

我创建了一个服务,以便可以从各种组件控制sidenav。我跟着this example

然后根据需要观察路由器的事件和关闭。在app.component.ts中:

this.router.events.subscribe(event => {
  // close sidenav on routing
  this.sidenavService.close();
});

如果您想关闭特定链接上的sidenav,这不起作用,但服务本身会促进这一点。

答案 2 :(得分:3)

受到@ isherwood的回答的启发,我想出了一个解决方案:

我创建了以下服务:

DECLARE @PERCENTAGE DECIMAL --Or INT if you prefer it
DECLARE @TOTAL DECIMAL --Or INT if you prefer it

SET @TOTAL = (SELECT COUNT(*) FROM VEHICLES_FW)

SET @PERCENTAGE = (SELECT COUNT(*) FROM VEHICLES_FW
WHERE ARCHIVE_STATUS_FW = 'N'
AND LOCATION_CODE_FW IN ('L0078')) * (100 / 180)

RETURN PERCENTAGE;

我更改了我的app组件,在上面的服务中设置了sideNav属性。

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

@Injectable()
export class SidenavService {

  public sideNav:MatSidenav;
  constructor() { }
}

请注意,实施export class AppComponent implements OnInit { title = 'app'; @ViewChild('sidenav') public sideNav:MatSidenav; constructor(private sidenavService: SidenavService) { } ngOnInit() { this.sidenavService.sideNav = this.sideNav; } } 并在OnInit功能中设置sidenavService.sideNav非常重要

然后,您可以在任何地方使用sideNavService。在我的情况下,我只在我在侧面导航菜单中实际链接的组件中使用它。

示例:

ngOnInit

您可能希望在更改参数而不是在init上执行此操作,但您明白了这一点。

答案 3 :(得分:2)

还有其他一些小信息,如果您只想在移动视口上关闭sidenav,只需在调用函数之前使用isHandset$函数检查抽屉状态:

import { ViewChild } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';

@ViewChild('snav', { static: false }) usuarioMenu: MatSidenav;

isHandset$: Observable<boolean> = 
   this.breakpointObserver.observe(Breakpoints.Handset)
    .pipe(
      map(result => result.matches),
      shareReplay()
    );

constructor(
    private breakpointObserver: BreakpointObserver) { }

  closeAllSidenav() {
    this.isHandset$.subscribe(isVisible => {
      if(isVisible) {
        this.myDrawer.close();
      }
    });
  }

答案 4 :(得分:1)

(click)="sidenav.close()"添加到mat-sidenav

<mat-sidenav #sidenav mode="side" class="app-sidenav" (click)="sidenav.close()">

答案 5 :(得分:0)

您不需要为此提供服务。这是一个简单的解决方案。

<mat-sidenav-container [hasBackdrop]="true">
                <mat-sidenav #sidenav mode="side" class="sideNavigation">
                        <mat-nav-list>
                                <a mat-list-item routerLink="" (click)="sidenav.close()"> bar</a>
                                <a mat-list-item routerLink="/bar" (click)="sidenav.close()">foo</a>
                                <a mat-list-item routerLink="/foo" (click)="sidenav.close()">whatever</a>
                                <a mat-list-item routerLink="/something1" (click)="sidenav.close()">SomePage</a>
                                <a mat-list-item routerLink="/something2" (click)="sidenav.close()">Some Page</a>
                        </mat-nav-list>
                </mat-sidenav>
                <mat-sidenav-content>
                        <mat-toolbar color="accent">
                                <mat-icon (click)="sidenav.toggle()">menu</mat-icon> 
                                <div class="divider"></div>
                                <img class="img" src="../assets/img/logo.png" alt="logo" (click)="goHome()" />
                        </mat-toolbar>
                        <router-outlet></router-outlet>
                </mat-sidenav-content>
        </mat-sidenav-container>

您要做的就是添加(click)="sidenav.close()"routerLink="/whatever/path/here"作品。这样将关闭sidenav定向到页面。

答案 6 :(得分:0)

在需要调用方法的情况下,我测试了另一种解决方案,使用@ViewChild似乎更容易,更实用,如果有人愿意,我将其留在这里。

app.component.html:

<mat-sidenav #snav mode="over" fixedTopGap="56">
  <mat-nav-list class="pt-0">
    <a mat-list-item (click)="closeAllSidenav()">
      Navigation Item
    </a>
  </mat-nav-list>
</mat-sidenav>

app.component.ts:

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

@ViewChild('snav', { static: false }) usuarioMenu: MatSidenav;

closeAllSidenav() {
  this.usuarioMenu.close();
}