Как сделать такое же поведение материала sidenav в angular 8?

Когда я загружаю страницу с компонентом Сиденав, меню слева закрывается. Как сделать так, чтобы меню открывалось по умолчанию и только после уменьшения ширины окна появлялась кнопка бургера, а само меню сворачивалось? Я хочу сделать то же самое https://material.angular.io/components/categories

Я создаю новый компонент, используя эту команду:

ng generate @angular/material:nav <component-name>

(https://material.angular.io/guide/schematics)

navigation.component.html

<mat-sidenav-container class = "sidenav-container">
  <mat-sidenav #drawer class = "sidenav" fixedInViewport
      [attr.role] = "(isHandset$ | async) ? 'dialog' : 'navigation'"
      [mode] = "(isHandset$ | async) ? 'over' : 'side'"
      [opened] = "(isHandset$ | async) === false">
    <mat-toolbar>Menu</mat-toolbar>
    <mat-nav-list>
      <a mat-list-item href = "/about">About</a>
      <a mat-list-item href = "/contact">Contact</a>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content>
    <mat-toolbar color = "primary">
      <button
        type = "button"
        aria-label = "Toggle sidenav"
        mat-icon-button
        (click) = "drawer.toggle()"
        *ngIf = "isHandset$ | async">
        <mat-icon aria-label = "Side nav toggle icon">menu</mat-icon>
      </button>
      <span>NavApp</span>
    </mat-toolbar>
    <router-outlet></router-outlet>
    <!-- Add Content Here -->
  </mat-sidenav-content>
</mat-sidenav-container>

navigation.component.ts

import { Component } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { map, share } from 'rxjs/operators';

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

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

  constructor(private breakpointObserver: BreakpointObserver) {}

}

когда я пытаюсь изменить [opened]="true" левое меню открывается, но нет привязки событий для this.breakpointObserver.observe(Breakpoints.Handset), и если я изменяю размер окна, левое меню не закрывается

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
0
1 795
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я считаю, что проблема заключается в том, что в вашем компоненте вы используете оператор share() для совместного использования наблюдаемого от this.breakpointObserver.observe() между четырьмя подписчиками (асинхронный канал) в вашем HTML-шаблоне.

Это означает, что этот наблюдаемый объект будет испускаться, когда он подписан на первый (в элементе <mat-sidenav>); эта эмиссия будет общей, но поскольку ваш элемент <button> имеет еще не создан, эмиссия слишком ранняя, и <button> никогда не получит ее. Это означает, что *ngIf на кнопке будет оцениваться как false при первой загрузке, даже если isHandset$ на самом деле выдал true, поэтому вы не увидите кнопку меню в мобильном представлении.

Чтобы решить эту проблему, вы можете использовать оператор shareReplay() вместо share(), который будет воспроизводить рассылку от this.breakpointObserver.observe() всем новым подписчикам (например, тому, что в <button>), даже если они были созданы после рассылки.

navigation.component.ts

import { Component } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';

@Component({
    selector: 'app-navigation',
    templateUrl: './navigation.component.html',
    styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent {
    isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
        .pipe(
            map(result => result.matches),
            shareReplay(1),
        );

    constructor(private breakpointObserver: BreakpointObserver) { }
}

можете объяснить подробнее, это действительно работает, но я не понимаю, почему

redk0m 27.07.2019 18:49

@ redk0m Я понял, что решение, которое я дал, было не очень хорошим, поэтому я обновил свой ответ, добавив лучшее решение с объяснением. Мой первоначальный ответ работал аналогично новому (гарантируя, что все подписчики в вашем шаблоне получили наблюдаемое), но, как вы видите в моем новом решении, не было необходимости создавать отдельные подписки для каждого асинхронного канала в шаблоне.

Collierre 27.07.2019 19:40

Возможно, чтобы добавить к этому, если кто-то хочет наблюдать за изменением определенной ширины, замените код breakpointObserver.observe следующим:

     isHandset$: Observable<boolean> = this.breakpointObserver.observe('(max-width: 720px)')
        .pipe(
            map(result => result.matches),
            shareReplay(1),
        );

Другие вопросы по теме