From 5d22f60216b145edc352793802066f5e9aac5347 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 12 Mar 2018 12:10:27 -0400 Subject: [PATCH] refactor(input): run autofill monitor outside the NgZone Switches the autofill monitor to run outside the `NgZone`, because it toggles classes on the element directly and it has the potential of being fired very often if the user has other animations on the element. Also adds a description to an output that is part of the public API. --- src/lib/input/autofill.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/lib/input/autofill.ts b/src/lib/input/autofill.ts index 163c9ff4c187..9bbf31cd3f08 100644 --- a/src/lib/input/autofill.ts +++ b/src/lib/input/autofill.ts @@ -14,7 +14,8 @@ import { Injectable, OnDestroy, OnInit, - Output + Output, + NgZone, } from '@angular/core'; import {Observable} from 'rxjs/Observable'; import {empty as observableEmpty} from 'rxjs/observable/empty'; @@ -50,7 +51,7 @@ const listenerOptions: any = supportsPassiveEventListeners() ? {passive: true} : export class AutofillMonitor implements OnDestroy { private _monitoredElements = new Map(); - constructor(private _platform: Platform) {} + constructor(private _platform: Platform, private _ngZone: NgZone) {} /** * Monitor for changes in the autofill state of the given input element. @@ -63,6 +64,7 @@ export class AutofillMonitor implements OnDestroy { } const info = this._monitoredElements.get(element); + if (info) { return info.subject.asObservable(); } @@ -71,15 +73,17 @@ export class AutofillMonitor implements OnDestroy { const listener = (event: AnimationEvent) => { if (event.animationName === 'mat-input-autofill-start') { element.classList.add('mat-input-autofilled'); - result.next({target: event.target as Element, isAutofilled: true}); + this._ngZone.run(() => result.next({target: event.target as Element, isAutofilled: true})); } else if (event.animationName === 'mat-input-autofill-end') { element.classList.remove('mat-input-autofilled'); - result.next({target: event.target as Element, isAutofilled: false}); + this._ngZone.run(() => result.next({target: event.target as Element, isAutofilled: false})); } }; - element.addEventListener('animationstart', listener, listenerOptions); - element.classList.add('mat-input-autofill-monitored'); + this._ngZone.runOutsideAngular(() => { + element.addEventListener('animationstart', listener, listenerOptions); + element.classList.add('mat-input-autofill-monitored'); + }); this._monitoredElements.set(element, { subject: result, @@ -118,6 +122,7 @@ export class AutofillMonitor implements OnDestroy { selector: '[matAutofill]', }) export class MatAutofill implements OnDestroy, OnInit { + /** Emits when the autofill state of the element changes. */ @Output() matAutofill: EventEmitter = new EventEmitter(); constructor(private _elementRef: ElementRef, private _autofillMonitor: AutofillMonitor) {}