fix(popover-edit): rework host listeners to account for changes in Ivy (#16060)

Switches all of the inherited event listeners in `popover-edit` to use `@HostListener`. In Ivy the `host` objects are merged when inheriting, whereas in ViewEngine they are overwritten. This means that with the current setup we'll end up with double event listeners once Ivy lands.
This commit is contained in:
Kristiyan Kostadinov
2019-05-21 01:38:04 +02:00
committed by mmalerba
parent 59fc0cb3e8
commit 558295b780
4 changed files with 50 additions and 19 deletions
@@ -7,7 +7,7 @@
*/
import {ReplaySubject} from 'rxjs';
import {Directive, ElementRef, EventEmitter, OnDestroy, OnInit} from '@angular/core';
import {Directive, ElementRef, EventEmitter, OnDestroy, OnInit, HostListener} from '@angular/core';
import {EDIT_PANE_SELECTOR} from './constants';
import {closest} from './polyfill';
import {EditRef} from './edit-ref';
@@ -23,13 +23,6 @@ export type PopoverEditClickOutBehavior = 'close' | 'submit' | 'noop';
*/
@Directive({
selector: 'form[cdkEditControl]',
host: {
'(ngSubmit)': 'handleFormSubmit()',
'(keydown.enter)': 'editRef.trackEnterPressForClose(true)',
'(keyup.enter)': 'editRef.trackEnterPressForClose(false)',
'(keyup.escape)': 'close()',
'(document:click)': 'handlePossibleClickOut($event)',
},
inputs: [
'clickOutBehavior: cdkEditControlClickOutBehavior',
'preservedFormValue: cdkEditControlPreservedFormValue',
@@ -79,6 +72,11 @@ export class CdkEditControl<FormValue> implements OnDestroy, OnInit {
* the form for validity before proceeding.
* Updates the revert state with the latest submitted value then closes the edit.
*/
// In Ivy the `host` metadata will be merged, whereas in ViewEngine it is overridden. In order
// to avoid double event listeners, we need to use `HostListener`. Once Ivy is the default, we
// can move this back into `host`.
// tslint:disable:no-host-decorator-in-concrete
@HostListener('ngSubmit')
handleFormSubmit(): void {
if (this.ignoreSubmitUnlessValid && !this.editRef.isValid()) { return; }
@@ -97,6 +95,11 @@ export class CdkEditControl<FormValue> implements OnDestroy, OnInit {
* Called on click anywhere in the document.
* If the click was outside of the lens, trigger the specified click out behavior.
*/
// In Ivy the `host` metadata will be merged, whereas in ViewEngine it is overridden. In order
// to avoid double event listeners, we need to use `HostListener`. Once Ivy is the default, we
// can move this back into `host`.
// tslint:disable:no-host-decorator-in-concrete
@HostListener('document:click', ['$event'])
handlePossibleClickOut(evt: Event): void {
if (closest(evt.target, EDIT_PANE_SELECTOR)) { return; }
@@ -113,6 +116,29 @@ export class CdkEditControl<FormValue> implements OnDestroy, OnInit {
}
}
// In Ivy the `host` metadata will be merged, whereas in ViewEngine it is overridden. In order
// to avoid double event listeners, we need to use `HostListener`. Once Ivy is the default, we
// can move this back into `host`.
// tslint:disable:no-host-decorator-in-concrete
@HostListener('keydown')
_handleKeydown() {
this.editRef.trackEnterPressForClose(true);
}
// In Ivy the `host` metadata will be merged, whereas in ViewEngine it is overridden. In order
// to avoid double event listeners, we need to use `HostListener`. Once Ivy is the default, we
// can move this back into `host`.
// tslint:disable:no-host-decorator-in-concrete
@HostListener('keyup', ['$event'])
_handleKeyup(event: KeyboardEvent) {
// TODO(crisbeto): should use cdk/keycodes once the tests are reworked to use cdk/testing.
if (event.key === 'Enter') {
this.editRef.trackEnterPressForClose(false);
} else if (event.key === 'Escape') {
this.close();
}
}
/** Triggers submit on tab out if clickOutBehavior is 'submit'. */
private _handleBlur(): void {
if (this.clickOutBehavior === 'submit') {
@@ -130,7 +156,6 @@ export class CdkEditControl<FormValue> implements OnDestroy, OnInit {
@Directive({
selector: 'button[cdkEditRevert]',
host: {
'(click)': 'revertEdit()',
'type': 'button', // Prevents accidental form submits.
}
})
@@ -138,6 +163,11 @@ export class CdkEditRevert<FormValue> {
constructor(
protected readonly editRef: EditRef<FormValue>) {}
// In Ivy the `host` metadata will be merged, whereas in ViewEngine it is overridden. In order
// to avoid double event listeners, we need to use `HostListener`. Once Ivy is the default, we
// can move this back into `host`.
// tslint:disable:no-host-decorator-in-concrete
@HostListener('click')
revertEdit(): void {
this.editRef.reset();
}
@@ -147,7 +177,6 @@ export class CdkEditRevert<FormValue> {
@Directive({
selector: 'button[cdkEditClose]',
host: {
'(click)': 'closeEdit()',
'type': 'button', // Prevents accidental form submits.
}
})
@@ -155,6 +184,11 @@ export class CdkEditClose<FormValue> {
constructor(
protected readonly editRef: EditRef<FormValue>) {}
// In Ivy the `host` metadata will be merged, whereas in ViewEngine it is overridden. In order
// to avoid double event listeners, we need to use `HostListener`. Once Ivy is the default, we
// can move this back into `host`.
// tslint:disable:no-host-decorator-in-concrete
@HostListener('click')
closeEdit(): void {
this.editRef.closeAfterEnterKeypress();
}
@@ -17,6 +17,7 @@ import {
OnDestroy,
TemplateRef,
ViewContainerRef,
HostListener,
} from '@angular/core';
import {fromEvent, merge, ReplaySubject} from 'rxjs';
import {debounceTime, filter, map, mapTo, startWith, takeUntil} from 'rxjs/operators';
@@ -393,7 +394,6 @@ export class CdkRowHoverContent implements AfterViewInit, OnDestroy {
*/
@Directive({
selector: '[cdkEditOpen]',
host: {'(click)': 'openEdit($event)'}
})
export class CdkEditOpen {
constructor(
@@ -408,6 +408,11 @@ export class CdkEditOpen {
}
}
// In Ivy the `host` metadata will be merged, whereas in ViewEngine it is overridden. In order
// to avoid double event listeners, we need to use `HostListener`. Once Ivy is the default, we
// can move this back into `host`.
// tslint:disable:no-host-decorator-in-concrete
@HostListener('click', ['$event'])
openEdit(evt: Event): void {
this.editEventDispatcher.editing.next(closest(this.elementRef.nativeElement!, CELL_SELECTOR));
evt.stopPropagation();
@@ -24,11 +24,6 @@ import {
@Directive({
selector: 'form[matEditLens]',
host: {
'(ngSubmit)': 'handleFormSubmit()',
'(keydown.enter)': 'editRef.trackEnterPressForClose(true)',
'(keyup.enter)': 'editRef.trackEnterPressForClose(false)',
'(keyup.escape)': 'close()',
'(document:click)': 'handlePossibleClickOut($event)',
'class': 'mat-edit-lens',
},
inputs: [
@@ -46,7 +41,6 @@ export class MatEditLens<FormValue> extends CdkEditControl<FormValue> {
@Directive({
selector: 'button[matEditRevert]',
host: {
'(click)': 'revertEdit()',
'type': 'button', // Prevents accidental form submits.
}
})
@@ -57,7 +51,6 @@ export class MatEditRevert<FormValue> extends CdkEditRevert<FormValue> {
@Directive({
selector: 'button[matEditClose]',
host: {
'(click)': 'closeEdit()',
'type': 'button', // Prevents accidental form submits.
}
})
@@ -107,7 +107,6 @@ export class MatRowHoverContent extends CdkRowHoverContent {
*/
@Directive({
selector: '[matEditOpen]',
host: {'(click)': 'openEdit($event)'}
})
export class MatEditOpen extends CdkEditOpen {
}