Skip to content

Commit

Permalink
fix(sidenav): container not reacting to changes to sidenavs added aft…
Browse files Browse the repository at this point in the history
…er init (#6161)

Fixes the sidenav container not reacting to sidenavs that were added after initialization.

Fixes #6127.
  • Loading branch information
crisbeto authored and tinayuangao committed Aug 1, 2017
1 parent 68e2f46 commit 0d80a77
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 19 deletions.
38 changes: 35 additions & 3 deletions src/lib/sidenav/sidenav.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ describe('MdSidenavContainer', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdSidenavModule, A11yModule, PlatformModule, NoopAnimationsModule],
declarations: [SidenavContainerTwoSidenavTestApp],
declarations: [SidenavContainerTwoSidenavTestApp, SidenavDelayed],
});

TestBed.compileComponents();
Expand Down Expand Up @@ -342,6 +342,26 @@ describe('MdSidenavContainer', () => {

expect(sidenavs.every(sidenav => sidenav.componentInstance.opened)).toBe(false);
}));

it('should animate the content when a sidenav is added at a later point', fakeAsync(() => {
const fixture = TestBed.createComponent(SidenavDelayed);

fixture.detectChanges();

const contentElement = fixture.debugElement.nativeElement.querySelector('.mat-sidenav-content');

expect(parseInt(contentElement.style.marginLeft)).toBe(0);

fixture.componentInstance.showSidenav = true;
fixture.detectChanges();

fixture.componentInstance.sidenav.open();
fixture.detectChanges();
tick();
fixture.detectChanges();

expect(parseInt(contentElement.style.marginLeft)).toBeGreaterThan(0);
}));
});


Expand All @@ -358,8 +378,7 @@ class SidenavContainerNoSidenavTestApp { }
</md-sidenav-container>`,
})
class SidenavContainerTwoSidenavTestApp {
@ViewChild(MdSidenavContainer)
sidenavContainer: MdSidenavContainer;
@ViewChild(MdSidenavContainer) sidenavContainer: MdSidenavContainer;
}

/** Test component that contains an MdSidenavContainer and one MdSidenav. */
Expand Down Expand Up @@ -441,3 +460,16 @@ class SidenavDynamicAlign {
class SidenavWitFocusableElements {
mode: string = 'over';
}


@Component({
template: `
<md-sidenav-container>
<md-sidenav *ngIf="showSidenav" #sidenav mode="side">Sidenav</md-sidenav>
</md-sidenav-container>
`,
})
class SidenavDelayed {
@ViewChild(MdSidenav) sidenav: MdSidenav;
showSidenav = false;
}
34 changes: 18 additions & 16 deletions src/lib/sidenav/sidenav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ import {animate, state, style, transition, trigger, AnimationEvent} from '@angul
import {Directionality, coerceBooleanProperty} from '../core';
import {FocusTrapFactory, FocusTrap} from '../core/a11y/focus-trap';
import {ESCAPE} from '../core/keyboard/keycodes';
import {first} from '../core/rxjs/index';
import {first, takeUntil, startWith} from '../core/rxjs/index';
import {DOCUMENT} from '@angular/platform-browser';
import {merge} from 'rxjs/observable/merge';


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

ngAfterContentInit() {
// On changes, assert on consistency.
this._sidenavs.changes.subscribe(() => this._validateDrawers());
this._sidenavs.forEach((sidenav: MdSidenav) => {
this._watchSidenavToggle(sidenav);
this._watchSidenavAlign(sidenav);
startWith.call(this._sidenavs.changes, null).subscribe(() => {
this._validateDrawers();
this._sidenavs.forEach((sidenav: MdSidenav) => {
this._watchSidenavToggle(sidenav);
this._watchSidenavAlign(sidenav);
});
});
this._validateDrawers();
}

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

if (sidenav.mode !== 'side') {
sidenav.onOpen.subscribe(() => this._setContainerClass(true));
sidenav.onClose.subscribe(() => this._setContainerClass(false));
takeUntil.call(merge(sidenav.onOpen, sidenav.onClose), this._sidenavs.changes).subscribe(() =>
this._setContainerClass(sidenav.opened));
}
}

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

Expand Down

0 comments on commit 0d80a77

Please sign in to comment.