1

I'm using mat-drawer to add sidenav to a page. I'm putting the drawer into a side-nav-container component that will be common to all pages so that each page can have the following structure:

<!-- a page in my app -->
<app-side-nav-container #container>

  <!-- Button to trigger side-nav to open or close -->
  <button type="button" mat-button (click)="container.tryToggle()">
    Toggle nav (from an element on the page)
  </button>

  Content in the rest of the page

</app-side-nav-container>

In the code above I'm triggering the toggle behaviour by calling a .tryToggle() method which exists on the side-nav-container element. I've used the #container notation to create a reference to the container component. This is that container component:

export class SideNavContainerComponent {

  @ViewChild('drawer')
  public drawer?: MatDrawer

  public tryToggle() :void {
    console.log('Toggling. drawer.opened=' + this.drawer?.opened)
    this.drawer?.toggle()
  }
}

.tryToggle() is accessible from the projected content but won't trigger the drawer

When I click "Toggle nav" in the projected content, the console.log call works as expected and prints the value of this.drawer?.opened. This value alternates between true and false.

enter image description here

However the drawer doesn't work. It won't open or close. It's very peculiar. It's not that the drawer is out of scope - it's in scope and I can print it into the console. It just doesn't open or close.

.tryToggle works when called by an element inside the container component

If I call exactly the same method but triggered by button inside the the parent component then it works.

// side-nav-container.html
<mat-drawer-container class="example-container" autosize>
  
  <mat-drawer #drawer mode="side">
    <p>Sidenav content </p>
  </mat-drawer>

  <div class="body-of-page">
    <ng-content></ng-content>
  </div>

  <!-- additional button to test behaviour... --> 
  <button type="button" mat-button (click)="tryToggle()">
    Toggle sidenav (this works)
  </button>
</mat-drawer-container>

What am I missing?

Peter Nixey
  • 16,187
  • 14
  • 79
  • 133
  • A similar question is already been asked -> https://stackoverflow.com/questions/37587732/how-to-call-another-components-function-in-angular2 – Shariq Dec 03 '20 at 14:05
  • This is a slightly different question. As far as I can tell, I've got no problem calling the method on the parent. I have access. the problem is that even with access, the drawer isn't responding to the method that is successfully called in the parent – Peter Nixey Dec 03 '20 at 14:58
  • Also this suffers from the same problem whether you trigger the opening via a service, an event or using the direct methodology above. I just can't get the sidenav to open unless I click in the actual nav container component – Peter Nixey Dec 03 '20 at 15:33
  • Try to call this.drawer?.toggle() inside setTimeout – Chellappan வ Dec 03 '20 at 16:26
  • @Chellappanவ - excellent suggestion. I kept considering that but then not doing it for some reason. It still fails though. I tried it on multiple delays one after the other and using `sidenav.open()` to be sure I wasn't accidentally toggling the wrong way. Still nothing though – Peter Nixey Dec 03 '20 at 17:10
  • 1
    Does your SideNavContainerComponent component use onpush change detection strategy? – Chellappan வ Dec 03 '20 at 17:27
  • 1
    Oh my god Chellappan. I was literally just coming back here to say that I'd fixed it by switching the change strategy from `OnPush`. I'm SO impressed that you figured this out in abstract. I did get there before you but I've also been working on this all day. Please can you at least put this into an answer so that I can give you some more points. – Peter Nixey Dec 03 '20 at 17:36

1 Answers1

1

Had a similar problem because of ChangeDetectionStrategy.OnPush.

I had to do an explicit call to markForCheck on the ChangeDetectorRef.

Matthieu Riegler
  • 31,918
  • 20
  • 95
  • 134