i would like to open the md-sidenav on large screen and close it on mobile device. What would be the right way to do it inside my application?
Is there any possibility to query the media inside angular2 component?
i would like to open the md-sidenav on large screen and close it on mobile device. What would be the right way to do it inside my application?
Is there any possibility to query the media inside angular2 component?
Inside of component class i've defined a reference to the sidenav and listening to the window resize events. Depending on the window.innerWith you can build your logic.
@ViewChild('sidenav') sidenav: MdSidenav
@HostListener('window:resize', ['$event'])
onResize(event) {
this.configureSideNav()
}
configureSideNav() {
this.smallScreen = window.innerWidth < 501 ? true : false
if (!this.smallScreen) {
this.sidenav.mode = "side"
this.sidenav.opened = true
} else {
this.sidenav.mode = 'over'
this.sidenav.opened = false
}
}
i've just found a little bit better approach to listen to screen changes in Angular: https://github.com/angular/flex-layout/wiki/ObservableMedia
it's a Angular Flex Layout module that provides the mediaQuery activations notifications as observable. so there is no need to listen to create a resize
listener manually.
besides, MediaChange
Class provides handy aliases (lg
, md
, xs
etc.) that can be used to make decisions about screen size-specific expressions.
check out examples on their wiki-page.
We have a dashboard component which is the layout container for the entire app.
dashboard.html:
<md-sidenav-layout class="sidenav-layout">
<bv-toolbar (toggleSidenav)="start.toggle()" [screenWidth]="screenWidth"></bv-toolbar>
<md-sidenav #start [opened]="screenWidth > 1000" [mode]="(screenWidth > 1000) ? 'side' : 'start'">
<bv-sidenav-content [user]="user$ | async" [screenWidth]="screenWidth" (navClose)="start.toggle()"></bv-sidenav-content>
</md-sidenav>
<div class="sidenav-content"></div>
</md-sidenav-layout>
Note how we send the screenWidth value from the dashboard to the toolbar (and sidenav) components via the template using [screenWidth]="screenWidth"
.
dashboard.ts:
...
export class DashboardComponent {
screenWidth: number;
...
constructor (private cdr: ChangeDetectorRef, private store: Store<fromRoot.State> ) {
var that = this;
// set screenWidth on page load
that.screenWidth = window.innerWidth;
window.onresize = () => {
// set screenWidth on screen size change
that.screenWidth = window.innerWidth;
that.cdr.detectChanges();
}
}
Now that the screenWidth
is set on our dashboard, and sent via the template to the other components, we need to receive it in the child-component's script using @Input()
and then it will be available in the child component's template as well.
toolbar.ts:
...
export class ToolbarComponent {
@Output() toggleSidenav = new EventEmitter();
@Input() screenWidth : number;
}
This will allow the toolbar's template to have access to the screenWidth
variable defined earlier in the dashboard, and to get updates every time it is being changed (so you can set the logic once in the dashboard and inherit that value everywhere across the app.
toolbar.html:
<md-toolbar color="primary">
<button md-icon-button
(click)="toggleSidenav.emit()"
[ngClass]="{'h-hide': screenWidth > 1000}">
<md-icon>menu</md-icon>
</button>
</md-toolbar>
I found the solution from another post: rxjs/behaviorsubject.
You can get the value of the width from BehaviorSubject.window. And I'm using it instead to switch the sidenav mode between "side" and "over".
windows.service.ts:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class WindowService {
public window = new BehaviorSubject(null);
public width: Observable<number>;
constructor() {
let windowSize = new BehaviorSubject(getWindowSize());
this.width = (windowSize.pluck('width') as Observable<number>).distinctUntilChanged();
Observable.fromEvent(window, 'resize')
.map(getWindowSize)
.subscribe(windowSize);
}
}
function getWindowSize() {
return {
width: window.innerWidth
};
}
component.ts:
ngOnInit() {
// Change sideNav mode between over and side depending on size of window
this.windowService.width.subscribe((width) => {
if (width) {
console.log(width);
if (width < 600) {
this.sideNavMode = "over"
} else {
this.sideNavMode = "side"
}
}
});
}
I solved this exact same issue today in my workplace. I have done it basically using the same approach that @AndyGrey pointed out. I thought the code sample might help someone.
sidenav-layout.component.ts
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { ObservableMedia, MediaChange } from '@angular/flex-layout';
import { MdSidenav } from '@angular/material';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'sidenav-layout',
templateUrl: './sidenav-layout.component.html',
styleUrls: [ './sidenav-layout.component.scss' ]
})
export class SidenavLayoutComponent implements OnInit, OnDestroy {
@ViewChild('sidenav') sidenav: MdSidenav;
private _mediaSubscription: Subscription;
sidenavOpen = true;
isMobile = false;
constructor(private media: ObservableMedia) {}
ngOnInit() {
this._mediaSubscription = this.media.asObservable().subscribe((change:
MediaChange) => {
this.isMobile = (change.mqAlias === 'xs') || (change.mqAlias === 'sm');
this.sidenavOpen = !this.isMobile;
});
}
onLinkClick() {
if (this.isMobile) {
this.sidenav.toggle();
}
}
ngOnDestroy() {
this._mediaSubscription.unsubscribe();
}
}
sidenav-layout.component.html
<md-sidenav #sidenav mode="side" opened={{sidenavOpen}}>
The onLinkClick() method should be added to all your list-items. So that whenever a link is clicked in the mobile view the sidenav will be toggled(hidden).
Well at the end do not forget to unsubscribe the mediaSubscription Observable :)
© 2022 - 2024 — McMap. All rights reserved.