Nicholas Foden
Nicholas Foden

Reputation: 156

Angular Material MdSidebar - How to call .toggle() from typescript

I am trying to sidenav toggle from another component, however when the .toggle() function gets called from my parent component it throws this error:

AppComponent.html:1 ERROR TypeError: this.sidenav.toggle is not a function at AppComponent.webpackJsonp.176.AppComponent.toggleNav (app.component.ts:25)

here is the code: app.component.ts

import { Component, ViewChild } from '@angular/core';
import { MaterialModule } from '@angular/material';
import { NavComponent } from './nav/nav.component';
import { SidebarComponent } from './sidebar/sidebar.component';
import { FooterComponent } from './footer/footer.component';
import { MdSidenav } from '@angular/material';
@Component({
    moduleId: module.id,
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})
export class AppComponent{
    title = 'CRS Management App';
    @ViewChild('sidenav') sidenav:MdSidenav;
    toggleNav(){
      this.sidenav.toggle();
    }
}

app.component.html:

<app-nav #navbar (nav)="toggleNav()"></app-nav>
<app-sidebar #sidenav></app-sidebar>
<app-footer></app-footer>

the (nav) is emitted from the app-nav component.

sidebar.component.ts:

@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html',
  styleUrls: ['./sidebar.component.scss']
})
export class SidebarComponent {
    title = 'CRS';

  constructor() { }

}

sidebar.component.html:

 <md-sidenav-container class="container">
<!--SIDEBAR -->
    <md-sidenav #sidebar class="sidebar" mode="over" opened="true">

        <!-- MENU https://material.angular.io/components/component/list -->
         <div class="nav-links">
            <md-nav-list> <!--TODO Links -->
               <a md-list-item href="/one"> Option </a> <!--TODO Icon -->
               <a md-list-item href="/two"> Option </a> <!--TODO Icon-->
               <a md-list-item href="/three"> Option </a> <!--TODO Icon-->
               <span class="flex"></span><!--TODO Divider-->
               <a md-list-item href="/four"> _______ </a> <!--TODO Icon-->
               <a md-list-item href="/five"> Option </a> <!--TODO Icon -->
               <a md-list-item href="/six"> Option </a> <!--TODO Icon-->
               <a md-list-item href="/seven"> Option </a> <!--TODO Icon-->
               <a md-list-item href="/eight"> Option </a> <!--TODO Icon-->
            </md-nav-list>
        <!-- SETTINGS -->
            <!--TODO link to settings -->
            <!--TODO Convert to md-list-item -->
            <button md-button class="md-icon-button" aria-label="Settings">
                Settings<md-icon>settings</md-icon> 
            </button>
        <!-- SETTINGS END -->
        </div>

    </md-sidenav>
<!-- SIDEBAR ENDS -->
<router-outlet></router-outlet>
</md-sidenav-container>

I have tried using AfterViewInit, it throws:

ERROR TypeError: this.sideNav.toggle is not a function at AppComponent.webpackJsonp.176.AppComponent.toggleNav (http://127.0.0.1:4200/main.bundle.js:171:22)

Upvotes: 5

Views: 8837

Answers (3)

JayChase
JayChase

Reputation: 11525

The template ref #sidenav on the AppComponent refers to the SidebarComponent which does not have a toggle function.

You could add one to it which then calls the sidenav.toggle() and then you could call that from the AppComponent.

sidebar.component.ts

  import { Component, OnInit, ViewChild } from '@angular/core';
  import { MatSidenav} from '@angular/material';

  @Component({
    selector: 'app-sidebar',
    templateUrl: './sidebar.component.html',
    styleUrls: ['./sidebar.component.css']
  })
  export class SidebarComponent implements OnInit {
    title = 'CRS';
    @ViewChild('sidenav') sidenav: MatSidenav;
    constructor() { }

    ngOnInit() {
    }

    toggle() {
      this.sidenav.toggle();
    }
  }

sidebar.component.html

  <md-sidenav-container class="container">
    <md-sidenav #sidenav class="sidebar" mode="over" opened="true">
    ...

    </md-sidenav>      
 </md-sidenav-container>

Upvotes: 9

kanagaraj palanisamy
kanagaraj palanisamy

Reputation: 397

In my case I didn't include MatSidenavModule in my component module imports list. That solved the problem. It looks like some other Material module has indirectly imports the SidenaveModule, that is the reason we didn't get the usual error when we don't import the module in our component.

Upvotes: 1

Evgeniy Chekan
Evgeniy Chekan

Reputation: 2655

Try to use ngAfterViewInit callback, here's a good example.

Upvotes: 0

Related Questions