Skip to content

Commit 559fdb6

Browse files
committed
remove ripple after timeout outside the angular zone
1 parent a2c6682 commit 559fdb6

File tree

4 files changed

+24
-12
lines changed

4 files changed

+24
-12
lines changed

src/lib/core/ripple/ripple-renderer.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
ElementRef,
3+
NgZone,
34
} from '@angular/core';
45

56
/** TODO: internal */
@@ -44,7 +45,9 @@ export class RippleRenderer {
4445
private _triggerElement: HTMLElement;
4546
_opacity: string;
4647

47-
constructor(_elementRef: ElementRef, private _eventHandlers: Map<string, (e: Event) => void>) {
48+
constructor(_elementRef: ElementRef,
49+
private _eventHandlers: Map<string, (e: Event) => void>,
50+
private _ngZone: NgZone) {
4851
this._rippleElement = _elementRef.nativeElement;
4952
// The background div is created in createBackgroundIfNeeded when the ripple becomes enabled.
5053
// This avoids creating unneeded divs when the ripple is always disabled.
@@ -143,8 +146,15 @@ export class RippleRenderer {
143146

144147
rippleDiv.addEventListener('transitionend',
145148
(event: TransitionEvent) => transitionEndCallback(ripple, event));
146-
// Remove the ripple after transitions (fade-in, transform, fade-out)
147-
setTimeout(() => this.removeRippleFromDom(ripple.rippleElement), fadeInSeconds * 3 * 1000);
149+
// Ensure that ripples are always removed, even when transitionend doesn't fire.
150+
// Run this outside the Angular zone because there's nothing that Angular cares about.
151+
// If it were to run inside the Angular zone, every test that used ripples would have to be
152+
// either async or fakeAsync.
153+
this._ngZone.runOutsideAngular(() => {
154+
// The ripple lasts a time equal to the sum of fade-in, transform, and fade-out (3 * fade-in time).
155+
let rippleDuration = fadeInSeconds * 3 * 1000;
156+
setTimeout(() => this.removeRippleFromDom(ripple.rippleElement), rippleDuration);
157+
});
148158
}
149159

150160
/** Fades out a foreground ripple after it has fully expanded and faded in. */

src/lib/core/ripple/ripple.spec.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {TestBed, ComponentFixture, fakeAsync, tick} from '@angular/core/testing';
1+
import {TestBed, ComponentFixture, async, tick} from '@angular/core/testing';
22
import {Component, ViewChild} from '@angular/core';
33
import {MdRipple, MdRippleModule} from './ripple';
44

@@ -128,12 +128,13 @@ describe('MdRipple', () => {
128128
expect(rippleElement.querySelectorAll('.md-ripple-foreground').length).toBe(0);
129129
});
130130

131-
it('removes foreground ripples after timeout', fakeAsync(() => {
131+
it('removes foreground ripples after timeout', async(() => {
132132
rippleElement.click();
133133
expect(rippleElement.querySelectorAll('.md-ripple-foreground').length).toBe(1);
134134

135-
tick(100);
136-
expect(rippleElement.querySelectorAll('.md-ripple-foreground').length).toBe(0);
135+
setTimeout(() => {
136+
expect(rippleElement.querySelectorAll('.md-ripple-foreground').length).toBe(0);
137+
}, 600);
137138
}));
138139

139140
it('creates ripples when manually triggered', () => {

src/lib/core/ripple/ripple.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ElementRef,
66
HostBinding,
77
Input,
8+
NgZone,
89
OnChanges,
910
OnDestroy,
1011
OnInit,
@@ -61,13 +62,13 @@ export class MdRipple implements OnInit, OnDestroy, OnChanges {
6162

6263
private _rippleRenderer: RippleRenderer;
6364

64-
constructor(_elementRef: ElementRef) {
65+
constructor(_elementRef: ElementRef, _ngZone: NgZone) {
6566
// These event handlers are attached to the element that triggers the ripple animations.
6667
const eventHandlers = new Map<string, (e: Event) => void>();
6768
eventHandlers.set('mousedown', (event: MouseEvent) => this._mouseDown(event));
6869
eventHandlers.set('click', (event: MouseEvent) => this._click(event));
6970
eventHandlers.set('mouseleave', (event: MouseEvent) => this._mouseLeave(event));
70-
this._rippleRenderer = new RippleRenderer(_elementRef, eventHandlers);
71+
this._rippleRenderer = new RippleRenderer(_elementRef, eventHandlers, _ngZone);
7172
}
7273

7374
/** TODO: internal */

src/lib/tabs/tab-nav-bar/tab-nav-bar.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Component, Input, ViewChild, ElementRef, ViewEncapsulation, Directive} from '@angular/core';
1+
import {Component, Input, ViewChild, ElementRef, ViewEncapsulation, Directive, NgZone} from '@angular/core';
22
import {MdInkBar} from '../ink-bar';
33
import {MdRipple} from '../../core/ripple/ripple';
44

@@ -51,7 +51,7 @@ export class MdTabLink {
5151
selector: '[md-tab-link]',
5252
})
5353
export class MdTabLinkRipple extends MdRipple {
54-
constructor(private _element: ElementRef) {
55-
super(_element);
54+
constructor(private _element: ElementRef, private _ngZone: NgZone) {
55+
super(_element, _ngZone);
5656
}
5757
}

0 commit comments

Comments
 (0)