I have two components, the AppNav component and the Machines component. The AppNav component has the toolbar and sidenav. I have also placed a filter button on the toolbar of the AppNav. In the Machines Component there's a mat-drawer which needs to be toggled after clicking on the filter button in the toolbar of the AppNav. The problem is I don't know how to make the two communicate. The Machines component is not a direct child of the AppNav component since I'm loading the other components (Machines, etc) via router-outlet placed in the sidenav-content of the AppNav.
Look at the components from below:
The DrawerService (that I thought of creating to maybe ease my frustration)
import { Injectable } from '@angular/core';
import { MatDrawer } from '@angular/material';
@Injectable({
providedIn: 'root'
})
export class DrawerService {
private drawer: MatDrawer;
/**
* setDrawer
*/
public setDrawer(flyout: MatDrawer) {
this.drawer = flyout;
}
/**
* open
*/
public open() {
return this.drawer.open();
}
/**
* close
*/
public close() {
return this.drawer.close();
}
/**
* toggle
*/
public toggle(): void {
this.drawer.toggle();
}
}
The Machines component (machines.component.ts)
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-machines',
templateUrl: './machines.component.html',
styleUrls: ['./machines.component.sass']
})
export class Machines implements OnInit {
constructor() { }
ngOnInit() {
}
}
The Machines html (machines.component.html)
<mat-drawer-container
fxFlexFill>
<mat-drawer
mode="side"
opened
position="end"
#flyout
class="mat-elevation-z3"
[style.width]="'200px'">
<mat-toolbar>
<span>Filter</span>
<span fxFlex></span>
<mat-icon
svgIcon="close"
(click)="flyout.toggle()"></mat-icon>
</mat-toolbar>
<mat-list>
<mat-list-item>01</mat-list-item>
<mat-list-item>02</mat-list-item>
<mat-list-item>03</mat-list-item>
<mat-list-item>04</mat-list-item>
</mat-list>
</mat-drawer>
<mat-drawer-content>
<div>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Saepe, id assumenda ratione quaerat at itaque dolorem sit ipsam, modi nam voluptatem nisi expedita quis possimus ea a sed neque? Iure!
</div>
</mat-drawer-content>
</mat-drawer-container>
The AppNav component (app-nav.component.ts)
import { Component, ViewChild, ViewChildren } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ThemeService } from '../services/theme.service';
import { DrawerService } from '../services/drawer.service';
import { MatDrawer } from '@angular/material';
@Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.sass']
})
export class AppNav {
yearTodate: number = new Date().getFullYear();
isDarkTheme: Observable<boolean>;
links: Array<Object>;
isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
.pipe(
map(result => result.matches)
);
@ViewChildren('flyout') public flyout: MatDrawer;
constructor(
private breakpointObserver: BreakpointObserver,
private drawerService: DrawerService,
private themeService: ThemeService) {}
ngOnInit() {
this.isDarkTheme = this.themeService.isDarkTheme;
this.links = this.linksArray;
this.drawerService.setDrawer(this.flyout);
}
toggleDarkTheme(checked: boolean) {
this.themeService.setDarkTheme(checked);
}
toggleFlyout () {
this.drawerService.toggle();
}
linksArray = [
{
route: "/dashboard",
icon: "ballot",
name: "Dashboard"
},
{
route: "/vehicles",
icon: "car",
name: "Vehicles"
}
]
}
The AppNav html (app-nav.component.html)
<div
[ngClass]="{'dark-theme': isDarkTheme | async}"
fxLayout="column"
fxLayoutAlign="center center"
fxFlexFill
class="mat-app-background"
style="position: relative">
<mat-sidenav-container class="sidenav-container">
<mat-sidenav
#drawer
class="sidenav mat-elevation-z3"
fixedInViewport="true"
[attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
[mode]="(isHandset$ | async) ? 'over' : 'side'"
[opened]="!(isHandset$ | async)"
fxLayout="column">
<mat-nav-list>
<a
mat-list-item
routerLink="{{link.route}}"
*ngFor="let link of links">
<mat-icon svgIcon="{{link.icon}}"></mat-icon>
<span fxFlex="5"></span>
<span>{{link.name}}</span>
</a>
</mat-nav-list>
<span fxFlex></span>
<mat-nav-list>
<a
mat-list-item
routerLink="/login">
<mat-icon svgIcon="login"></mat-icon>
<span fxFlex="5"></span>
<span>Login</span>
</a>
</mat-nav-list>
<mat-divider></mat-divider>
<small
style="padding: 16px">
©{{yearTodate}} MotionPlus
</small>
</mat-sidenav>
<mat-sidenav-content
fxLayout="column">
<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"
svgIcon="menu">
<!-- menu -->
</mat-icon>
</button>
<span>MotionPlus</span>
<span fxFlex></span>
<button
mat-icon-button
(click)="toggleFlyout()">
<mat-icon svgIcon="filter-variant"></mat-icon>
</button>
<button
mat-icon-button
[matMenuTriggerFor]="bucket">
<mat-icon
svgIcon="format-color-fill"></mat-icon>
</button>
<mat-menu
#bucket="matMenu">
<button
mat-menu-item
(click)="toggleDarkTheme(true)"
fxLayout="column"
fxLayoutAlign="center center">
<span
style="
background: purple;
width: 42px;
height: 42px;
border-radius: 50%">
</span>
</button>
<button
mat-menu-item
(click)="toggleDarkTheme(false)"
fxLayout="column"
fxLayoutAlign="center center">
<span
style="
background: yellow;
width: 42px;
height: 42px;
border-radius: 50%">
</span>
</button>
</mat-menu>
</mat-toolbar>
<!-- Add Content Here -->
<div
style="padding: 0 24px;"
fxFlex>
<router-outlet></router-outlet>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
</div>
Point me in the right direction on how I can achieve this. I want to control the opening and closing of the mat-drawer that is in the Machines component (which loads dynamically via router-outlet) from the AppNav component.
The component where drawer exists
export class DashboardComponent implements OnInit {
@ViewChild('drawer') public drawer: MatDrawer;
ngOnInit() {
this.toolbarService.setDrawer(this.drawer);
}
}
Component with the toggle button. This is a child of the component with the drawer:
export class PageToolbarComponent implements OnInit {
toggleDrawer() {
this.toolbarService.toggle();
}
}
Shared service:
private drawer: MatDrawer;
setDrawer(drawer: MatDrawer) {
this.drawer = drawer;
}
toggle(): void {
this.drawer.toggle();
}
This worked for me. For more details
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With