components: [MdSidenav] - Sidenav Resizing Regression

Bug, feature request, or proposal:

Bug/Regression from 2.0.0-beta.8.

Also a feature request for an API to allow triggering recalculations for the MdSidenavContainer/MdDrawerContainer, or being able to update _styles manually and having the view update…

What is the expected behavior?

In the previous release 2.0.0-beta.8 the sidenav resized when the window was resized.

I have a responsive sidenav that uses Angular flex-layout for showing/hiding responsive content in the sidenav when the view changes from md to lg and vice-versa.

What is the current behavior?

In 2.0.0-beta.10 this is no longer the case. The changes made in #6189 made the sidenav update only when the sidenav is opening/closing.

Since flex-layout’s changes occur without having to call open() or close() on the sidenav, the width recalculation doesn’t occur.

example

What are the steps to reproduce?

Put dynamic/responsive content within a sidenav that is configured with “side”.

What is the use-case or motivation for changing an existing behavior?

Being able to dynamically call a refresh of the MdSidenav/MdDrawer or MdSidenavContainer/MdDrawerContainer.

Even better would be an accessor to allow manually setting the margin of the sidenav to allow for pre-computing the _style variable and updating it when needed.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular 4.3.5 Angular Material 2.0.0-beta.10

Is there anything else we should know?

This is similar to #6583.

For right now I am using the following hack in my navigation directive to workaround whenever the ObservableMedia from angular flex-layout changes:

// Timeout required for flex-layout directives to update the child views/the width.
setTimeout(() => {
            (this._container as any)._updateStyles();
            (this._container as any)._changeDetectorRef.markForCheck();
}, 0);

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 26
  • Comments: 42 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I definitely think we need to do something about this, even if its just making some of these methods public so people can trigger update manually. Raising the priority.

Here is my solution: HTML

<md-sidenav-container #container>
    <md-sidenav  mode="side" opened="{{showMenu}}" class="shadow"></md-sidenav>
    <div class="my-content"></div>
</md-sidenav-container>

TS

export class MyComponent implements OnInit, AfterViewInit {
    @ViewChild('container') private _container;
    public showMenu: boolean = false;
    ...
    ngAfterViewInit() {
      setTimeout(()=>{
        this.showMenu = true;
      },0);
      this._container._ngZone.onMicrotaskEmpty.subscribe(() => {
        this._container._updateStyles();
        this._container._changeDetectorRef.markForCheck();
      })
    };
    ...
}

@josephperrott I think the issues are about different things. The one you referenced is about opening and closing the sidenav automatically when viewport width changes. This one is about being able to resize the sidenav width while keeping it open.

Before the last update this worked with no problem. Right now, the main content is not being resized when the sidebar width is resized. Some people have shared workarounds for this, but I think it would be nice if Angular Material would support this use case which is quite popular in places like firebase.

Opened Closed
image image

this.sidenavContainer.autosize = true;

worked for me… after mucking with it for an hour. 😦

I was using @ghwyf workaround until beta.11 as well. What worked for me in beta.12 is the following:

export class MyComponent implements OnInit, AfterViewInit {
    @ViewChild('container') private _container;
    public showMenu: boolean = false;
    ...
    ngAfterViewInit() {
      setTimeout(()=>{
        this.showMenu = true;
      },0);
      this._container._ngZone.onMicrotaskEmpty.subscribe(() => {
        this._container._updateContentMargins();
        this._container._changeDetectorRef.markForCheck();
      })
    };
    ...
}

Same issue after upgrading from 2.0.0-beta.8 to 2.0.0-beta.10

My workarround :

app.component.html

<md-sidenav class="main-sidenav" #sidenav mode="side" opened="false">

app.component.ts

export class AppComponent implements  AfterViewInit {

  @ViewChild('sidenav') 
  private sidenav: MdSidenav;

  ngAfterViewInit(): void {
    setTimeout(() => {
      this.sidenav.open();
    }, 250);
  }
}

@dereekb this issue should not be closed. Still exists in the year 2019. @bobbydowling solution is the only thing worked for me. And I mucked with it for like 3 hours.

@crisbeto is the resize function on a roadmap for sidenav? Would it not suffice to add a “closeTo” option which, when in side mode and when set, does not transform to visibility hidden but sets the drawer width to whatever was closeTo was set to?

Same problem here after upgrading to 2.0.0-beta.10 . The fix from @ghwyf doesn’t work for me with angular 4.4.4

Reopening, sorry I misunderstood a bit there.

Closing as duplicate of #1130

Come on, wheres the fix…?

@mmalerba

I think exposing a method to reflow the sizenav is reasonable, most component with on push should be able to reflow based on a users request.

That said, it’s not developer friendly and verbose… nothing serious since a drawer is not used frequently in an app but still requires work. From what I see, in most of the use cases the developer will set the width value of a sidenav which is easy since it’s a user defined dom element… If we create an @Input for the width on sidenav we can automatically trigger the changes on the content element which is hidden from the developer.

This is automatic and does not require work from the dev.

The solution should be a public method + width input just in case

This solution is still a bit of a hack, but it’s less of a hack than setTimeout…

@ViewChild('sidenavContainer') private sidenavContainer: MatSidenavContainer;

this.sidenavContainer._contentMarginChanges
    .pipe(
        debounceTime(250),
        tap(() => this.sidenavContainer._contentMargins.left = this.sidenav._width),
    )
    .subscribe();

Same. This is still an issue in 6.4.7

Yep still an issue in 6.4.7 "@angular/material": "^6.4.7"

Still happening in 6.4.7:

image

 "dependencies": {
    "@angular/animations": "6.1.8",
    "@angular/cdk": "^6.4.7",
    "@angular/common": "6.1.8",
    "@angular/compiler": "^6.1.8",
    "@angular/core": "6.1.8",
    "@angular/flex-layout": "^6.0.0-beta.18",
    "@angular/forms": "^6.1.8",
    "@angular/http": "6.1.8",
    "@angular/material": "^6.4.7",
    "@angular/platform-browser": "6.1.8",
    "@angular/platform-browser-dynamic": "6.1.8",
    "@angular/router": "6.1.8",
    "@angular/service-worker": "6.1.8",
    "@auth0/angular-jwt": "^2.0.0",
    "@ngx-formly/core": "^4.7.2",
    "@ngx-formly/material": "^4.7.2",
    "@ngx-translate/core": "^10.0.2",
    "@ngx-translate/http-loader": "^3.0.1",
    "core-js": "^2.5.2",
    "hammerjs": "^2.0.8",
    "material-design-icons-iconfont": "^3.0.3",
    "moment": "^2.22.1",
    "rxjs": "^6.3.2",
    "url": "^0.11.0",
    "util": "^0.11.0",
    "zone.js": "^0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^0.8.3",
    "@angular/cli": "^6.2.3",
    "@angular/compiler-cli": "^6.1.8",
    "@angular/language-service": "6.1.8",
    "@biesbjerg/ngx-translate-extract": "^2.3.1",
    "@ngx-rocket/scripts": "^2.1.0",
    "@types/jasmine": "^2.5.52",
    "@types/jasminewd2": "^2.0.2",
    "@types/lodash": "^4.14.103",
    "@types/node": "^8.9.4",
    "codelyzer": "^4.1.0",
    "htmlhint": "^0.10.1",
    "https-proxy-agent": "^2.0.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "^4.2.1",
    "karma": "^3.0.0",
    "karma-chrome-launcher": "^2.2.0",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "^1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "karma-junit-reporter": "^1.2.0",
    "protractor": "^5.4.0",
    "stylelint": "~9.1.1",
    "stylelint-config-recommended-scss": "~3.1.0",
    "stylelint-config-standard": "~18.2.0",
    "stylelint-scss": "~2.5.0",
    "ts-node": "~5.0.0",
    "tslint": "~5.9.1",
    "typescript": "^2.9.2"
  }

@crisbeto thanks! Wonderful.

How does one achieve the minification of the sidenav now? Animations? Is there an example? Can I toggle to a certain width?

Thanks

Here’s my temporary workaround to fix it:

<md-sidenav-container #sideNavContainer>
  <md-sidenav #sideNav align="start" mode="{{navMode}}" opened="true"
    [@sideNavAnim] (@sideNavAnim.done)="onSideNavAnimDone($event)">
    <!-- sidenav content -->
  </md-sidenav>
  <!-- primary content -->
  <router-outlet *ngIf="sideNavAnimFinished"></router-outlet>
</md-sidenav-container>
export class MyComponent {
  navMode = 'side';
  sideNavAnimFinished = false;
  ...
  onSideNavAnimDone(event) {
    this.sideNavAnimFinished = true;
  }
}