Reputation: 3
When I load the page with the sidenav component, the menu on the left is closed. How to make the menu open by default and only after reducing the window width, did the burger button appear and the menu itself collapsed? I want to do the same https://material.angular.io/components/categories
I crate new component use that command:
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) {}
}
when i try change [opened]="true" left menu is opened, but no event binding for this.breakpointObserver.observe(Breakpoints.Handset) and if i resize window left menu not closed
Upvotes: 0
Views: 2053
Reputation: 266
To perhaps add to this, in case someone is looking to observe a change on a specific width, replace the breakpointObserver.observe code with this:
isHandset$: Observable<boolean> = this.breakpointObserver.observe('(max-width: 720px)')
.pipe(
map(result => result.matches),
shareReplay(1),
);
Upvotes: 0
Reputation: 956
I believe the problem you have is that in your component you are using the share()
operator to share the observable from this.breakpointObserver.observe()
among the four subscribers (async pipe) in your HTML template.
This means that this observable will emit when it is first subscribed to (in the <mat-sidenav>
element); this emission will be shared, but as your <button>
element has not yet been created, the emission is too early and the <button>
will never receive it. This means that the *ngIf
on the button will evaluate to false on first load, even if isHandset$
has actually emitted true, so you will not see the menu button on mobile view.
To solve this you can use the shareReplay()
operator instead of share()
, which will replay the emission from this.breakpointObserver.observe()
to all new subscribers (e.g. the one in <button>
), even if they have been created after the emission.
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) { }
}
Upvotes: 2