Skip to content

Commit 43d8b3f

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 e79f7f9 commit 43d8b3f

File tree

2 files changed

+53
-19
lines changed

2 files changed

+53
-19
lines changed

src/lib/sidenav/sidenav.spec.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ describe('MdSidenavContainer', () => {
313313
beforeEach(async(() => {
314314
TestBed.configureTestingModule({
315315
imports: [MdSidenavModule, A11yModule, PlatformModule, NoopAnimationsModule],
316-
declarations: [SidenavContainerTwoSidenavTestApp],
316+
declarations: [SidenavContainerTwoSidenavTestApp, SidenavDelayed],
317317
});
318318

319319
TestBed.compileComponents();
@@ -342,6 +342,26 @@ describe('MdSidenavContainer', () => {
342342

343343
expect(sidenavs.every(sidenav => sidenav.componentInstance.opened)).toBe(false);
344344
}));
345+
346+
it('should animate the content when a sidenav is added at a later point', fakeAsync(() => {
347+
const fixture = TestBed.createComponent(SidenavDelayed);
348+
349+
fixture.detectChanges();
350+
351+
const contentElement = fixture.debugElement.nativeElement.querySelector('.mat-sidenav-content');
352+
353+
expect(parseInt(contentElement.style.marginLeft)).toBe(0);
354+
355+
fixture.componentInstance.showSidenav = true;
356+
fixture.detectChanges();
357+
358+
fixture.componentInstance.sidenav.open();
359+
fixture.detectChanges();
360+
tick();
361+
fixture.detectChanges();
362+
363+
expect(parseInt(contentElement.style.marginLeft)).toBeGreaterThan(0);
364+
}));
345365
});
346366

347367

@@ -358,8 +378,7 @@ class SidenavContainerNoSidenavTestApp { }
358378
</md-sidenav-container>`,
359379
})
360380
class SidenavContainerTwoSidenavTestApp {
361-
@ViewChild(MdSidenavContainer)
362-
sidenavContainer: MdSidenavContainer;
381+
@ViewChild(MdSidenavContainer) sidenavContainer: MdSidenavContainer;
363382
}
364383

365384
/** Test component that contains an MdSidenavContainer and one MdSidenav. */
@@ -441,3 +460,16 @@ class SidenavDynamicAlign {
441460
class SidenavWitFocusableElements {
442461
mode: string = 'over';
443462
}
463+
464+
465+
@Component({
466+
template: `
467+
<md-sidenav-container>
468+
<md-sidenav *ngIf="showSidenav" #sidenav mode="side">Sidenav</md-sidenav>
469+
</md-sidenav-container>
470+
`,
471+
})
472+
class SidenavDelayed {
473+
@ViewChild(MdSidenav) sidenav: MdSidenav;
474+
showSidenav = false;
475+
}

src/lib/sidenav/sidenav.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ import {animate, state, style, transition, trigger, AnimationEvent} from '@angul
2828
import {Directionality, coerceBooleanProperty} from '../core';
2929
import {FocusTrapFactory, FocusTrap} from '../core/a11y/focus-trap';
3030
import {ESCAPE} from '../core/keyboard/keycodes';
31-
import {first} from '../core/rxjs/index';
31+
import {first, takeUntil, startWith} from '../core/rxjs/index';
3232
import {DOCUMENT} from '@angular/platform-browser';
33+
import {merge} from 'rxjs/observable/merge';
3334

3435

3536
/** Throws an exception when two MdSidenav are matching the same side. */
@@ -336,13 +337,13 @@ export class MdSidenavContainer implements AfterContentInit {
336337
}
337338

338339
ngAfterContentInit() {
339-
// On changes, assert on consistency.
340-
this._sidenavs.changes.subscribe(() => this._validateDrawers());
341-
this._sidenavs.forEach((sidenav: MdSidenav) => {
342-
this._watchSidenavToggle(sidenav);
343-
this._watchSidenavAlign(sidenav);
340+
startWith.call(this._sidenavs.changes, null).subscribe(() => {
341+
this._validateDrawers();
342+
this._sidenavs.forEach((sidenav: MdSidenav) => {
343+
this._watchSidenavToggle(sidenav);
344+
this._watchSidenavAlign(sidenav);
345+
});
344346
});
345-
this._validateDrawers();
346347
}
347348

348349
/** Calls `open` of both start and end sidenavs */
@@ -361,16 +362,17 @@ export class MdSidenavContainer implements AfterContentInit {
361362
* is properly hidden.
362363
*/
363364
private _watchSidenavToggle(sidenav: MdSidenav): void {
364-
sidenav._animationStarted.subscribe(() => {
365-
// Set the transition class on the container so that the animations occur. This should not
366-
// be set initially because animations should only be triggered via a change in state.
367-
this._renderer.addClass(this._element.nativeElement, 'mat-sidenav-transition');
368-
this._changeDetectorRef.markForCheck();
369-
});
365+
takeUntil.call(sidenav._animationStarted, this._sidenavs.changes)
366+
.subscribe(() => {
367+
// Set the transition class on the container so that the animations occur. This should not
368+
// be set initially because animations should only be triggered via a change in state.
369+
this._renderer.addClass(this._element.nativeElement, 'mat-sidenav-transition');
370+
this._changeDetectorRef.markForCheck();
371+
});
370372

371373
if (sidenav.mode !== 'side') {
372-
sidenav.onOpen.subscribe(() => this._setContainerClass(true));
373-
sidenav.onClose.subscribe(() => this._setContainerClass(false));
374+
takeUntil.call(merge(sidenav.onOpen, sidenav.onClose), this._sidenavs.changes).subscribe(() =>
375+
this._setContainerClass(sidenav.opened));
374376
}
375377
}
376378

@@ -384,7 +386,7 @@ export class MdSidenavContainer implements AfterContentInit {
384386
}
385387
// NOTE: We need to wait for the microtask queue to be empty before validating,
386388
// since both drawers may be swapping sides at the same time.
387-
sidenav.onAlignChanged.subscribe(() =>
389+
takeUntil.call(sidenav.onAlignChanged, this._sidenavs.changes).subscribe(() =>
388390
first.call(this._ngZone.onMicrotaskEmpty).subscribe(() => this._validateDrawers()));
389391
}
390392

0 commit comments

Comments
 (0)