Skip to content

Commit b9da8a5

Browse files
committed
fix(sidenav): container not reacting to changes to sidenavs added after init
Fixes the sidenav container not reacting to sidenavs that were added after initialization. Fixes #6127.
1 parent 846899d commit b9da8a5

File tree

2 files changed

+49
-21
lines changed

2 files changed

+49
-21
lines changed

src/lib/sidenav/sidenav.spec.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,7 @@ describe('MdSidenavContainer', () => {
459459
beforeEach(async(() => {
460460
TestBed.configureTestingModule({
461461
imports: [MdSidenavModule, A11yModule, PlatformModule],
462-
declarations: [
463-
SidenavContainerTwoSidenavTestApp
464-
],
462+
declarations: [SidenavContainerTwoSidenavTestApp, SidenavDelayed],
465463
});
466464

467465
TestBed.compileComponents();
@@ -490,6 +488,23 @@ describe('MdSidenavContainer', () => {
490488
});
491489
}));
492490
});
491+
492+
it('should animate the content when a sidenav is added at a later point', () => {
493+
const fixture = TestBed.createComponent(SidenavDelayed);
494+
495+
fixture.detectChanges();
496+
497+
const contentElement = fixture.debugElement.nativeElement.querySelector('.mat-sidenav-content');
498+
499+
expect(parseInt(contentElement.style.marginLeft)).toBe(0);
500+
501+
fixture.componentInstance.showSidenav = true;
502+
fixture.detectChanges();
503+
fixture.componentInstance.sidenav.open();
504+
fixture.detectChanges();
505+
506+
expect(parseInt(contentElement.style.marginLeft)).toBeGreaterThan(0);
507+
});
493508
});
494509

495510

@@ -506,8 +521,7 @@ class SidenavContainerNoSidenavTestApp { }
506521
</md-sidenav-container>`,
507522
})
508523
class SidenavContainerTwoSidenavTestApp {
509-
@ViewChild(MdSidenavContainer)
510-
sidenavContainer: MdSidenavContainer;
524+
@ViewChild(MdSidenavContainer) sidenavContainer: MdSidenavContainer;
511525
}
512526

513527
/** Test component that contains an MdSidenavContainer and one MdSidenav. */
@@ -601,3 +615,16 @@ class SidenavDynamicAlign {
601615
class SidenavWitFocusableElements {
602616
mode: string = 'over';
603617
}
618+
619+
620+
@Component({
621+
template: `
622+
<md-sidenav-container>
623+
<md-sidenav *ngIf="showSidenav" #sidenav mode="side">Sidenav</md-sidenav>
624+
</md-sidenav-container>
625+
`,
626+
})
627+
class SidenavDelayed {
628+
@ViewChild(MdSidenav) sidenav: MdSidenav;
629+
showSidenav = false;
630+
}

src/lib/sidenav/sidenav.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
import {Directionality, coerceBooleanProperty} from '../core';
2828
import {FocusTrapFactory, FocusTrap} from '../core/a11y/focus-trap';
2929
import {ESCAPE} from '../core/keyboard/keycodes';
30-
import {first} from '../core/rxjs/index';
30+
import {first, takeUntil, startWith} from '../core/rxjs/index';
3131
import {DOCUMENT} from '@angular/platform-browser';
3232
import {merge} from 'rxjs/observable/merge';
3333

@@ -372,13 +372,13 @@ export class MdSidenavContainer implements AfterContentInit {
372372
}
373373

374374
ngAfterContentInit() {
375-
// On changes, assert on consistency.
376-
this._sidenavs.changes.subscribe(() => this._validateDrawers());
377-
this._sidenavs.forEach((sidenav: MdSidenav) => {
378-
this._watchSidenavToggle(sidenav);
379-
this._watchSidenavAlign(sidenav);
375+
startWith.call(this._sidenavs.changes, null).subscribe(() => {
376+
this._validateDrawers();
377+
this._sidenavs.forEach((sidenav: MdSidenav) => {
378+
this._watchSidenavToggle(sidenav);
379+
this._watchSidenavAlign(sidenav);
380+
});
380381
});
381-
this._validateDrawers();
382382
}
383383

384384
/** Calls `open` of both start and end sidenavs */
@@ -401,16 +401,17 @@ export class MdSidenavContainer implements AfterContentInit {
401401
* is properly hidden.
402402
*/
403403
private _watchSidenavToggle(sidenav: MdSidenav): void {
404-
merge(sidenav.onOpenStart, sidenav.onCloseStart).subscribe(() => {
405-
// Set the transition class on the container so that the animations occur. This should not
406-
// be set initially because animations should only be triggered via a change in state.
407-
this._renderer.addClass(this._element.nativeElement, 'mat-sidenav-transition');
408-
this._changeDetectorRef.markForCheck();
409-
});
404+
takeUntil.call(merge(sidenav.onOpenStart, sidenav.onCloseStart), this._sidenavs.changes)
405+
.subscribe(() => {
406+
// Set the transition class on the container so that the animations occur. This should not
407+
// be set initially because animations should only be triggered via a change in state.
408+
this._renderer.addClass(this._element.nativeElement, 'mat-sidenav-transition');
409+
this._changeDetectorRef.markForCheck();
410+
});
410411

411412
if (sidenav.mode !== 'side') {
412-
sidenav.onOpen.subscribe(() => this._setContainerClass(true));
413-
sidenav.onClose.subscribe(() => this._setContainerClass(false));
413+
takeUntil.call(merge(sidenav.onOpen, sidenav.onClose), this._sidenavs.changes).subscribe(() =>
414+
this._setContainerClass(sidenav.opened));
414415
}
415416
}
416417

@@ -424,7 +425,7 @@ export class MdSidenavContainer implements AfterContentInit {
424425
}
425426
// NOTE: We need to wait for the microtask queue to be empty before validating,
426427
// since both drawers may be swapping sides at the same time.
427-
sidenav.onAlignChanged.subscribe(() =>
428+
takeUntil.call(sidenav.onAlignChanged, this._sidenavs.changes).subscribe(() =>
428429
first.call(this._ngZone.onMicrotaskEmpty).subscribe(() => this._validateDrawers()));
429430
}
430431

0 commit comments

Comments
 (0)