From 72d56b095f5d3d29d6cef5d82992a1d65ad47268 Mon Sep 17 00:00:00 2001 From: arturovt Date: Tue, 15 Mar 2022 19:27:14 +0200 Subject: [PATCH] fix(material/input): resolve memory leak on iOS --- src/material/input/input.ts | 42 +++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/material/input/input.ts b/src/material/input/input.ts index d27ce4db7e47..6af7c3e98379 100644 --- a/src/material/input/input.ts +++ b/src/material/input/input.ts @@ -308,24 +308,7 @@ export class MatInput // exists on iOS, we only bother to install the listener on iOS. if (_platform.IOS) { ngZone.runOutsideAngular(() => { - _elementRef.nativeElement.addEventListener('keyup', (event: Event) => { - const el = event.target as HTMLInputElement; - - // Note: We specifically check for 0, rather than `!el.selectionStart`, because the two - // indicate different things. If the value is 0, it means that the caret is at the start - // of the input, whereas a value of `null` means that the input doesn't support - // manipulating the selection range. Inputs that don't support setting the selection range - // will throw an error so we want to avoid calling `setSelectionRange` on them. See: - // https://html.spec.whatwg.org/multipage/input.html#do-not-apply - if (!el.value && el.selectionStart === 0 && el.selectionEnd === 0) { - // Note: Just setting `0, 0` doesn't fix the issue. Setting - // `1, 1` fixes it for the first time that you type text and - // then hold delete. Toggling to `1, 1` and then back to - // `0, 0` seems to completely fix it. - el.setSelectionRange(1, 1); - el.setSelectionRange(0, 0); - } - }); + _elementRef.nativeElement.addEventListener('keyup', this._iOSKeyupListener); }); } @@ -360,6 +343,10 @@ export class MatInput if (this._platform.isBrowser) { this._autofillMonitor.stopMonitoring(this._elementRef.nativeElement); } + + if (this._platform.IOS) { + this._elementRef.nativeElement.removeEventListener('keyup', this._iOSKeyupListener); + } } ngDoCheck() { @@ -519,4 +506,23 @@ export class MatInput const element = this._elementRef.nativeElement as HTMLSelectElement; return this._isNativeSelect && (element.multiple || element.size > 1); } + + private _iOSKeyupListener = (event: Event): void => { + const el = event.target as HTMLInputElement; + + // Note: We specifically check for 0, rather than `!el.selectionStart`, because the two + // indicate different things. If the value is 0, it means that the caret is at the start + // of the input, whereas a value of `null` means that the input doesn't support + // manipulating the selection range. Inputs that don't support setting the selection range + // will throw an error so we want to avoid calling `setSelectionRange` on them. See: + // https://html.spec.whatwg.org/multipage/input.html#do-not-apply + if (!el.value && el.selectionStart === 0 && el.selectionEnd === 0) { + // Note: Just setting `0, 0` doesn't fix the issue. Setting + // `1, 1` fixes it for the first time that you type text and + // then hold delete. Toggling to `1, 1` and then back to + // `0, 0` seems to completely fix it. + el.setSelectionRange(1, 1); + el.setSelectionRange(0, 0); + } + }; }