Template-driven value (currentState): {{ currentState }}
- Template-driven dirty: {{ modelDir?.dirty }}
+ Template-driven dirty: {{ modelDir ? modelDir.dirty : false }}
diff --git a/src/lib/menu/menu.spec.ts b/src/lib/menu/menu.spec.ts
index 7f9a1bccfbd..61b562001bb 100644
--- a/src/lib/menu/menu.spec.ts
+++ b/src/lib/menu/menu.spec.ts
@@ -590,7 +590,7 @@ describe('MdMenu', () => {
subscription.unsubscribe();
});
- it('should toggle a nested menu when its trigger is hovered', () => {
+ it('should toggle a nested menu when its trigger is hovered', fakeAsync(() => {
compileTestComponent();
instance.rootTriggerEl.nativeElement.click();
fixture.detectChanges();
@@ -607,33 +607,39 @@ describe('MdMenu', () => {
dispatchMouseEvent(items[items.indexOf(levelOneTrigger) + 1], 'mouseenter');
fixture.detectChanges();
+ tick(500);
+
expect(overlay.querySelectorAll('.mat-menu-panel').length).toBe(1, 'Expected one open menu');
expect(levelOneTrigger.classList)
.not.toContain('mat-menu-item-highlighted', 'Expected the trigger to not be highlighted');
- });
+ }));
- it('should close all the open sub-menus when the hover state is changed at the root', () => {
- compileTestComponent();
- instance.rootTriggerEl.nativeElement.click();
- fixture.detectChanges();
+ it('should close all the open sub-menus when the hover state is changed at the root',
+ fakeAsync(() => {
+ compileTestComponent();
+ instance.rootTriggerEl.nativeElement.click();
+ fixture.detectChanges();
- const items = Array.from(overlay.querySelectorAll('.mat-menu-panel [md-menu-item]'));
- const levelOneTrigger = overlay.querySelector('#level-one-trigger')!;
+ const items = Array.from(overlay.querySelectorAll('.mat-menu-panel [md-menu-item]'));
+ const levelOneTrigger = overlay.querySelector('#level-one-trigger')!;
- dispatchMouseEvent(levelOneTrigger, 'mouseenter');
- fixture.detectChanges();
+ dispatchMouseEvent(levelOneTrigger, 'mouseenter');
+ fixture.detectChanges();
- const levelTwoTrigger = overlay.querySelector('#level-two-trigger')! as HTMLElement;
- dispatchMouseEvent(levelTwoTrigger, 'mouseenter');
- fixture.detectChanges();
+ const levelTwoTrigger = overlay.querySelector('#level-two-trigger')! as HTMLElement;
+ dispatchMouseEvent(levelTwoTrigger, 'mouseenter');
+ fixture.detectChanges();
- expect(overlay.querySelectorAll('.mat-menu-panel').length)
- .toBe(3, 'Expected three open menus');
+ expect(overlay.querySelectorAll('.mat-menu-panel').length)
+ .toBe(3, 'Expected three open menus');
- dispatchMouseEvent(items[items.indexOf(levelOneTrigger) + 1], 'mouseenter');
- fixture.detectChanges();
- expect(overlay.querySelectorAll('.mat-menu-panel').length).toBe(1, 'Expected one open menu');
- });
+ dispatchMouseEvent(items[items.indexOf(levelOneTrigger) + 1], 'mouseenter');
+ fixture.detectChanges();
+ tick(500);
+
+ expect(overlay.querySelectorAll('.mat-menu-panel').length)
+ .toBe(1, 'Expected one open menu');
+ }));
it('should open a nested menu when its trigger is clicked', () => {
compileTestComponent();
@@ -653,7 +659,7 @@ describe('MdMenu', () => {
.toBe(2, 'Expected repeat clicks not to close the menu.');
});
- it('should open and close a nested menu with arrow keys in ltr', () => {
+ it('should open and close a nested menu with arrow keys in ltr', fakeAsync(() => {
compileTestComponent();
instance.rootTriggerEl.nativeElement.click();
fixture.detectChanges();
@@ -669,11 +675,12 @@ describe('MdMenu', () => {
expect(panels.length).toBe(2, 'Expected two open menus');
dispatchKeyboardEvent(panels[1], 'keydown', LEFT_ARROW);
fixture.detectChanges();
+ tick(500);
expect(overlay.querySelectorAll('.mat-menu-panel').length).toBe(1);
- });
+ }));
- it('should open and close a nested menu with the arrow keys in rtl', () => {
+ it('should open and close a nested menu with the arrow keys in rtl', fakeAsync(() => {
dir = 'rtl';
fixture.destroy();
compileTestComponent();
@@ -691,9 +698,10 @@ describe('MdMenu', () => {
expect(panels.length).toBe(2, 'Expected two open menus');
dispatchKeyboardEvent(panels[1], 'keydown', RIGHT_ARROW);
fixture.detectChanges();
+ tick(500);
expect(overlay.querySelectorAll('.mat-menu-panel').length).toBe(1);
- });
+ }));
it('should not do anything with the arrow keys for a top-level menu', () => {
compileTestComponent();
@@ -713,7 +721,7 @@ describe('MdMenu', () => {
.toBe(1, 'Expected one menu to remain open');
});
- it('should close all of the menus when the backdrop is clicked', () => {
+ it('should close all of the menus when the backdrop is clicked', fakeAsync(() => {
compileTestComponent();
instance.rootTriggerEl.nativeElement.click();
fixture.detectChanges();
@@ -733,9 +741,10 @@ describe('MdMenu', () => {
(overlay.querySelector('.cdk-overlay-backdrop')! as HTMLElement).click();
fixture.detectChanges();
+ tick(500);
expect(overlay.querySelectorAll('.mat-menu-panel').length).toBe(0, 'Expected no open menus');
- });
+ }));
it('should shift focus between the sub-menus', () => {
compileTestComponent();
@@ -858,7 +867,7 @@ describe('MdMenu', () => {
expect(Math.round(triggerRect.top)).toBe(Math.round(panelRect.top) + MENU_PANEL_TOP_PADDING);
});
- it('should close all of the menus when an item is clicked', () => {
+ it('should close all of the menus when an item is clicked', fakeAsync(() => {
compileTestComponent();
instance.rootTriggerEl.nativeElement.click();
fixture.detectChanges();
@@ -875,9 +884,10 @@ describe('MdMenu', () => {
(menus[2].querySelector('.mat-menu-item')! as HTMLElement).click();
fixture.detectChanges();
+ tick(500);
expect(overlay.querySelectorAll('.mat-menu-panel').length).toBe(0, 'Expected no open menus');
- });
+ }));
it('should set a class on the menu items that trigger a sub-menu', () => {
compileTestComponent();
@@ -911,37 +921,40 @@ describe('MdMenu', () => {
.toContain('mat-elevation-z4', 'Expected second sub-menu to have base elevation + 2.');
});
- it('should update the elevation when the same menu is opened at a different depth', () => {
- compileTestComponent();
- instance.rootTrigger.openMenu();
- fixture.detectChanges();
+ it('should update the elevation when the same menu is opened at a different depth',
+ fakeAsync(() => {
+ compileTestComponent();
+ instance.rootTrigger.openMenu();
+ fixture.detectChanges();
- instance.levelOneTrigger.openMenu();
- fixture.detectChanges();
+ instance.levelOneTrigger.openMenu();
+ fixture.detectChanges();
- instance.levelTwoTrigger.openMenu();
- fixture.detectChanges();
+ instance.levelTwoTrigger.openMenu();
+ fixture.detectChanges();
- let lastMenu = overlay.querySelectorAll('.mat-menu-panel')[2];
+ let lastMenu = overlay.querySelectorAll('.mat-menu-panel')[2];
- expect(lastMenu.classList)
- .toContain('mat-elevation-z4', 'Expected menu to have the base elevation plus two.');
+ expect(lastMenu.classList)
+ .toContain('mat-elevation-z4', 'Expected menu to have the base elevation plus two.');
- (overlay.querySelector('.cdk-overlay-backdrop')! as HTMLElement).click();
- fixture.detectChanges();
+ (overlay.querySelector('.cdk-overlay-backdrop')! as HTMLElement).click();
+ fixture.detectChanges();
+ tick(500);
- expect(overlay.querySelectorAll('.mat-menu-panel').length).toBe(0, 'Expected no open menus');
+ expect(overlay.querySelectorAll('.mat-menu-panel').length)
+ .toBe(0, 'Expected no open menus');
- instance.alternateTrigger.openMenu();
- fixture.detectChanges();
+ instance.alternateTrigger.openMenu();
+ fixture.detectChanges();
- lastMenu = overlay.querySelector('.mat-menu-panel') as HTMLElement;
+ lastMenu = overlay.querySelector('.mat-menu-panel') as HTMLElement;
- expect(lastMenu.classList)
- .not.toContain('mat-elevation-z4', 'Expected menu not to maintain old elevation.');
- expect(lastMenu.classList)
- .toContain('mat-elevation-z2', 'Expected menu to have the proper updated elevation.');
- });
+ expect(lastMenu.classList)
+ .not.toContain('mat-elevation-z4', 'Expected menu not to maintain old elevation.');
+ expect(lastMenu.classList)
+ .toContain('mat-elevation-z2', 'Expected menu to have the proper updated elevation.');
+ }));
it('should not increase the elevation if the user specified a custom one', () => {
const elevationFixture = TestBed.createComponent(NestedMenuCustomElevation);
diff --git a/src/lib/package.json b/src/lib/package.json
index b6ea8b0c0f1..d077b8b5d8e 100644
--- a/src/lib/package.json
+++ b/src/lib/package.json
@@ -23,8 +23,8 @@
"homepage": "https://github.com/angular/material2#readme",
"peerDependencies": {
"@angular/cdk": "0.0.0-PLACEHOLDER",
- "@angular/core": "^4.0.0",
- "@angular/common": "^4.0.0"
+ "@angular/core": "^4.3.0",
+ "@angular/common": "^4.3.0"
},
"dependencies": {
"tslib": "^1.7.1"
diff --git a/src/lib/sidenav/sidenav.spec.ts b/src/lib/sidenav/sidenav.spec.ts
index 3a27dc4feba..b0c3d316a19 100644
--- a/src/lib/sidenav/sidenav.spec.ts
+++ b/src/lib/sidenav/sidenav.spec.ts
@@ -31,7 +31,6 @@ describe('MdSidenav', () => {
let fixture = TestBed.createComponent(BasicTestApp);
fixture.detectChanges();
- tick();
let testComponent: BasicTestApp = fixture.debugElement.componentInstance;
let sidenav = fixture.debugElement.query(By.directive(MdSidenav));
@@ -44,6 +43,7 @@ describe('MdSidenav', () => {
expect(testComponent.closeCount).toBe(0);
tick();
+ fixture.detectChanges();
expect(sidenav.componentInstance._isAnimating).toBe(false);
expect(testComponent.openCount).toBe(1);
@@ -58,6 +58,7 @@ describe('MdSidenav', () => {
expect(testComponent.closeCount).toBe(0);
tick();
+ fixture.detectChanges();
expect(testComponent.openCount).toBe(1);
expect(testComponent.closeCount).toBe(1);
@@ -105,7 +106,6 @@ describe('MdSidenav', () => {
let fixture = TestBed.createComponent(BasicTestApp);
fixture.detectChanges();
- tick();
let testComponent: BasicTestApp = fixture.debugElement.componentInstance;
let sidenav = fixture.debugElement.query(By.directive(MdSidenav));
@@ -162,7 +162,6 @@ describe('MdSidenav', () => {
let fixture = TestBed.createComponent(BasicTestApp);
fixture.detectChanges();
- tick();
let sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance;
let openButton = fixture.componentInstance.openButton.nativeElement;
diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts
index 47d90947b8f..b2b995674b0 100644
--- a/src/lib/sidenav/sidenav.ts
+++ b/src/lib/sidenav/sidenav.ts
@@ -71,12 +71,13 @@ export class MdSidenavToggleResult {
visibility: 'hidden',
})),
transition('void => open-instant', animate('0ms')),
- transition('void <=> open', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)'))
+ transition('void <=> open, open-instant => void',
+ animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)'))
])
],
host: {
'class': 'mat-sidenav',
- '[@transform]': '_getAnimationState()',
+ '[@transform]': '_animationState',
'(@transform.start)': '_onAnimationStart()',
'(@transform.done)': '_onAnimationEnd($event)',
'(keydown)': 'handleKeydown($event)',
@@ -129,6 +130,9 @@ export class MdSidenav implements AfterContentInit, OnDestroy {
/** Whether the sidenav is animating. Used to prevent overlapping animations. */
_isAnimating = false;
+ /** Current state of the sidenav animation. */
+ _animationState: 'open-instant' | 'open' | 'void' = 'void';
+
/**
* Promise that resolves when the open/close animation completes. It is here for backwards
* compatibility and should be removed next time we do sidenav breaking changes.
@@ -186,7 +190,7 @@ export class MdSidenav implements AfterContentInit, OnDestroy {
ngAfterContentInit() {
this._focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement);
this._focusTrap.enabled = this.isFocusTrapEnabled;
- Promise.resolve().then(() => this._enableAnimations = true);
+ this._enableAnimations = true;
}
ngOnDestroy() {
@@ -223,6 +227,13 @@ export class MdSidenav implements AfterContentInit, OnDestroy {
toggle(isOpen: boolean = !this.opened): Promise {
if (!this._isAnimating) {
this._opened = isOpen;
+
+ if (isOpen) {
+ this._animationState = this._enableAnimations ? 'open' : 'open-instant';
+ } else {
+ this._animationState = 'void';
+ }
+
this._currentTogglePromise = new Promise(resolve => {
first.call(isOpen ? this.onOpen : this.onClose).subscribe(resolve);
});
@@ -232,7 +243,7 @@ export class MdSidenav implements AfterContentInit, OnDestroy {
}
}
- // TODO(crisbeto): This promise is here backwards-compatibility.
+ // TODO(crisbeto): This promise is here for backwards-compatibility.
// It should be removed next time we do breaking changes in the sidenav.
return this._currentTogglePromise!;
}
@@ -248,17 +259,6 @@ export class MdSidenav implements AfterContentInit, OnDestroy {
}
}
- /**
- * Figures out the state of the sidenav animation.
- */
- _getAnimationState(): 'open-instant' | 'open' | 'void' {
- if (this.opened) {
- return this._enableAnimations ? 'open' : 'open-instant';
- }
-
- return 'void';
- }
-
_onAnimationStart() {
this._isAnimating = true;
this._animationStarted.emit();
@@ -273,8 +273,13 @@ export class MdSidenav implements AfterContentInit, OnDestroy {
this.onClose.emit(new MdSidenavToggleResult('close', true));
}
- this._isAnimating = false;
- this._currentTogglePromise = null;
+ // Note: as of Angular 4.3, the animations module seems to fire the `start` callback before
+ // the end if animations are disabled. Make this call async to ensure that it still fires
+ // at the appropriate time.
+ Promise.resolve().then(() => {
+ this._isAnimating = false;
+ this._currentTogglePromise = null;
+ });
}
get _width() {
diff --git a/src/material-examples/package.json b/src/material-examples/package.json
index bddb9cae984..e4f029d0dfa 100644
--- a/src/material-examples/package.json
+++ b/src/material-examples/package.json
@@ -24,9 +24,9 @@
"homepage": "https://github.com/angular/material2#readme",
"peerDependencies": {
"@angular/cdk": "0.0.0-PLACEHOLDER",
- "@angular/core": "^4.0.0",
- "@angular/common": "^4.0.0",
- "@angular/http": "^4.0.0",
+ "@angular/core": "^4.3.0",
+ "@angular/common": "^4.3.0",
+ "@angular/http": "^4.3.0",
"@angular/material": "0.0.0-PLACEHOLDER"
},
"dependencies": {
diff --git a/tools/screenshot-test/package.json b/tools/screenshot-test/package.json
index 9f5ae91cf24..485555b28bc 100644
--- a/tools/screenshot-test/package.json
+++ b/tools/screenshot-test/package.json
@@ -11,16 +11,16 @@
"dependencies": {
"@angular/animations": "^4.0.2",
"@angular/cdk": "angular/cdk-builds",
- "@angular/common": "^4.0.0",
- "@angular/compiler": "^4.0.0",
- "@angular/compiler-cli": "^4.0.0",
- "@angular/core": "^4.0.0",
- "@angular/forms": "^4.0.0",
- "@angular/http": "^4.0.0",
+ "@angular/common": "^4.3.0",
+ "@angular/compiler": "^4.3.0",
+ "@angular/compiler-cli": "^4.3.0",
+ "@angular/core": "^4.3.0",
+ "@angular/forms": "^4.3.0",
+ "@angular/http": "^4.3.0",
"@angular/material": "angular/material2-builds",
- "@angular/platform-browser": "^4.0.0",
- "@angular/platform-browser-dynamic": "^4.0.0",
- "@angular/router": "^4.0.0",
+ "@angular/platform-browser": "^4.3.0",
+ "@angular/platform-browser-dynamic": "^4.3.0",
+ "@angular/router": "^4.3.0",
"core-js": "^2.4.1",
"firebase": "^3.7.6",
"rxjs": "^5.0.1",
@@ -29,7 +29,7 @@
},
"devDependencies": {
"@angular/cli": "^1.0.0",
- "@angular/compiler-cli": "^4.0.0",
+ "@angular/compiler-cli": "^4.3.0",
"@types/node": "^6.0.42",
"ts-node": "1.2.1",
"typescript": "~2.2.1"