Skip to content

Commit ab78c14

Browse files
committed
remove ripple after timeout outside the angular zone
1 parent 011783c commit ab78c14

File tree

4 files changed

+31
-9
lines changed

4 files changed

+31
-9
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

@@ -132,12 +132,13 @@ describe('MdRipple', () => {
132132
expect(rippleElement.querySelectorAll('.md-ripple-foreground').length).toBe(0);
133133
});
134134

135-
it('removes foreground ripples after timeout', fakeAsync(() => {
135+
it('removes foreground ripples after timeout', async(() => {
136136
rippleElement.click();
137137
expect(rippleElement.querySelectorAll('.md-ripple-foreground').length).toBe(1);
138138

139-
tick(100);
140-
expect(rippleElement.querySelectorAll('.md-ripple-foreground').length).toBe(0);
139+
setTimeout(() => {
140+
expect(rippleElement.querySelectorAll('.md-ripple-foreground').length).toBe(0);
141+
}, 600);
141142
}));
142143

143144
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,
@@ -62,13 +63,13 @@ export class MdRipple implements OnInit, OnDestroy, OnChanges {
6263

6364
private _rippleRenderer: RippleRenderer;
6465

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

7475
/** TODO: internal */

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<<<<<<< HEAD
12
import {
23
Component,
34
Input,
@@ -8,6 +9,9 @@ import {
89
OnDestroy,
910
} from '@angular/core';
1011

12+
=======
13+
import {Component, Input, ViewChild, ElementRef, ViewEncapsulation, Directive, NgZone} from '@angular/core';
14+
>>>>>>> 559fdb6... remove ripple after timeout outside the angular zone
1115
import {MdInkBar} from '../ink-bar';
1216
import {MdRipple} from '../../core/ripple/ripple';
1317

@@ -59,9 +63,15 @@ export class MdTabLink {
5963
@Directive({
6064
selector: '[md-tab-link], [mat-tab-link]',
6165
})
66+
<<<<<<< HEAD
6267
export class MdTabLinkRipple extends MdRipple implements OnDestroy {
6368
constructor(private _element: ElementRef) {
6469
super(_element);
70+
=======
71+
export class MdTabLinkRipple extends MdRipple {
72+
constructor(private _element: ElementRef, private _ngZone: NgZone) {
73+
super(_element, _ngZone);
74+
>>>>>>> 559fdb6... remove ripple after timeout outside the angular zone
6575
}
6676

6777
// In certain cases the parent destroy handler

0 commit comments

Comments
 (0)