Open KlausHans opened 6 years ago
It looks like a change detection issue. It's not exactly ideal, but you can use the start and done handlers on the animation to start and stop a requestAnimationFrame
ticker that will trigger the appropriate change detection: https://stackblitz.com/edit/angular-o5fjz1?file=app/app.component.ts
@crisbeto Any way you can think of that we can do this for people?
I'm not sure whether there's an efficient way to do it, apart from using a ResizeObserver
which has pretty bad browser support. For these kinds of cases it might be better to make _updateContentMargins
a part of the public API so people can trigger a recalculation manually.
With the latest Angular (Material) version the behavior changed slightly. But its still broken. https://stackblitz.com/edit/angular-kzia2e @angular/animations7.2.9 @angular/cdk7.3.5 @angular/common7.2.9 @angular/compiler7.2.9 @angular/core7.2.9 @angular/material7.3.5
I'm facing a similar issue - I adjust the width of the side-nav from 200 to 79 pixels:
sidenav component sets its width internally with hostbinding:
@HostBinding('style.width') width = '200px';
toggleCollapse() {
this.collapse = !this.collapse;
this.width = this.collapse ? '79px' : '200px'
}
but mat-sidenav-content margin-left stays at 200px when the side-nav changes to 79px. It makes collapsing the side-nav redundant.
<mat-sidenav-container>
<mat-sidenav
#sidenav
[autoSize]="true" <--- INVALID, NOT AN OPTION FOR MAT-SIDENAV
[mode]="(isBarkMobile$ | async) ? 'over': 'side'"
[opened]="sideNavOpen"
[disableClose]="true"
[fixedInViewport]="(isBarkMobile$ | async)"
[fixedTopGap]="0"
[fixedBottomGap]="0">
<shared-sidenav (closeSideNav)="closeSideNavIfMobile()"> <-- WIDTH ADJUSTS 200 -> 79!!
</shared-sidenav>
</mat-sidenav>
<mat-sidenav-content> <-- MARGIN-RIGHT STAYS AT 200PX and doesnt go to 79px
<router-outlet></router-outlet>
<div style="display: none">
<!-- preload these icons -->
<mat-icon svgIcon="close-2"></mat-icon>
<mat-icon svgIcon="offline"></mat-icon>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
Here's my temporary fix:
toggleCollapse() {
this.collapse = !this.collapse;
this.width = this.collapse ? '79px' : '200px'
document.querySelector('.mat-drawer-content.mat-sidenav-content').style.marginLeft = this.width;
}
Still broken. https://stackblitz.com/edit/angular-rf4mmn
@angular/animations9.1.0
@angular/cdk9.2.0
@angular/common9.1.0
@angular/compiler9.1.0
@angular/core9.1.0
@angular/forms9.1.0
@angular/material9.2.0
@angular/platform-browser9.1.0
@angular/platform-browser-dynamic9.1.0
@angular/router9.1.0
Any updates on this?
this workaround with setTimeout worked for me
export class AppComponent implements AfterViewInit {
@ViewChild('sidenav')
private sidenav: MdSidenav;
ngAfterViewInit(): void {
setTimeout(() => {
this.sidenav.open();
}, 250);
}
}
Source: https://github.com/angular/components/issues/6743#issuecomment-327416089
I have been having these same issues and I have not been able to find a way to animate the width change of the drawer with the current functionality of these components. This is just one thing that I don't think was taken into consideration when the autosize
functionality was added. It works great as long as the width of the drawer is not animated.
The main problem I have encountered is the 'mat-drawer-transition' css class. It doesn't get added until the drawer is toggled for the first time so the content container won't animate unless the drawer has been toggled and once added it causes issues with the animations if you animate the width of the drawer. The original issue reported here is caused by this.
My temporary solution to this is to add an appropriately named directive to the MatSidenav or MatDrawer component.
@Directive({
selector: "[appDrawerAutosizeHack]",
})
export class DrawerAutosizeHackDirective implements OnInit, OnDestroy {
constructor(
@Optional() @Self() @Host() drawer: MatDrawer,
@Optional() @Self() @Host() sidenav: MatSidenav,
@Optional() drawerContainer: MatDrawerContainer,
@Optional() sidenavContainer: MatSidenavContainer,
@Optional() @Inject(DOCUMENT) private _doc: Document,
private _el: ElementRef<HTMLElement>
) {
this._drawer = drawer ?? sidenav;
this._container = drawerContainer ?? sidenavContainer;
}
private _drawer?: MatDrawer | MatSidenav;
private _container?: MatDrawerContainer | MatSidenavContainer;
private _destroyed = new Subject<void>();
private resizeObserver?: ResizeObserver;
ngOnInit(): void {
this._drawer?.openedChange
.pipe(takeUntil(this._destroyed))
.subscribe(() => {
this._doc
.querySelector(".mat-drawer-transition")
?.classList.remove("mat-drawer-transition");
});
this.resizeObserver = new ResizeObserver((entries) => {
this._container?.updateContentMargins();
});
this.resizeObserver.observe(this._el.nativeElement);
}
ngOnDestroy(): void {
this._destroyed.next();
this._destroyed.complete();
this.resizeObserver?.unobserve(this._el.nativeElement);
}
}
This just simply removes the 'mat-drawer-transition' class and manually updates the content margins of the container. This is not ideal because it relies on implementation details (the name of the css class and the fact that it is added each time the animation starts) but it does keep this hack isolated. Doing this also means that the autosize
property on the container is superfluous.
The easiest fix for this is to change the MatDrawerContainer class to add the 'mat-drawer-transition' class when the drawer animation starts and remove it when it ends. This would allow developers to handle their own functionality if they want to transition the drawer size.
Bug, feature request, or proposal:
Bug
What is the expected behavior?
The size of the content area is calculated correctly according to the width of the sidenav menu.
What is the current behavior?
The calculation is wrong. The margin-left value of the content area is inverted to the width defined in the animation.
What are the steps to reproduce?
https://stackblitz.com/edit/angular-etpys5 (to see the issue you have to click a few times on the expand button)
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
@angular/material@5.2.0 @angular/cdk@5.2.0 @angular/core@5.2.4 @angular/animations@5.2.4