Skip to content

perf(popover-edit): collect common services into a single class for dependency injection #15797

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/cdk-experimental/popover-edit/edit-services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {Injectable, NgZone} from '@angular/core';
import {FocusTrapFactory} from '@angular/cdk/a11y';
import {Overlay} from '@angular/cdk/overlay';
import {ScrollDispatcher, ViewportRuler} from '@angular/cdk/scrolling';

import {EditEventDispatcher} from './edit-event-dispatcher';
import {FocusDispatcher} from './focus-dispatcher';
import {PopoverEditPositionStrategyFactory} from './popover-edit-position-strategy-factory';

/**
* Optimization
* Collects multiple Injectables into a singleton shared across the table. By reducing the
* number of services injected into each CdkPopoverEdit, this saves about 0.023ms of cpu time
* and 56 bytes of memory per instance.
*/
@Injectable()
export class EditServices {
constructor(
readonly editEventDispatcher: EditEventDispatcher, readonly focusDispatcher: FocusDispatcher,
readonly focusTrapFactory: FocusTrapFactory, readonly ngZone: NgZone,
readonly overlay: Overlay, readonly positionFactory: PopoverEditPositionStrategyFactory,
readonly scrollDispatcher: ScrollDispatcher, readonly viewportRuler: ViewportRuler) {}
}
2 changes: 1 addition & 1 deletion src/cdk-experimental/popover-edit/popover-edit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ const testCases: ReadonlyArray<[Type<BaseTestComponent>, string]> = [
];

describe('CDK Popover Edit', () => {
for (const [componentClass, label] of testCases.slice(0, 1)) {
for (const [componentClass, label] of testCases) {
describe(label, () => {
let component: BaseTestComponent;
let fixture: ComponentFixture<BaseTestComponent>;
Expand Down
82 changes: 27 additions & 55 deletions src/cdk-experimental/popover-edit/table-directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {FocusTrap, FocusTrapFactory} from '@angular/cdk/a11y';
import {Overlay, OverlayRef, PositionStrategy} from '@angular/cdk/overlay';
import {FocusTrap} from '@angular/cdk/a11y';
import {OverlayRef, PositionStrategy} from '@angular/cdk/overlay';
import {TemplatePortal} from '@angular/cdk/portal';
import {ScrollDispatcher, ViewportRuler} from '@angular/cdk/scrolling';
import {
AfterViewInit,
Directive,
Expand All @@ -25,14 +24,14 @@ import {debounceTime, filter, map, mapTo, startWith, takeUntil} from 'rxjs/opera

import {CELL_SELECTOR, EDIT_PANE_CLASS, EDIT_PANE_SELECTOR, ROW_SELECTOR} from './constants';
import {EditEventDispatcher} from './edit-event-dispatcher';
import {EditServices} from './edit-services';
import {FocusDispatcher} from './focus-dispatcher';
import {
FocusEscapeNotifier,
FocusEscapeNotifierDirection,
FocusEscapeNotifierFactory
} from './focus-escape-notifier';
import {closest} from './polyfill';
import {PopoverEditPositionStrategyFactory} from './popover-edit-position-strategy-factory';

/**
* Describes the number of columns before and after the originating cell that the
Expand All @@ -57,7 +56,7 @@ const DEFAULT_MOUSE_MOVE_DELAY_MS = 30;
*/
@Directive({
selector: 'table[editable], cdk-table[editable], mat-table[editable]',
providers: [EditEventDispatcher],
providers: [EditEventDispatcher, EditServices],
})
export class CdkEditable implements AfterViewInit, OnDestroy {
protected readonly destroyed = new ReplaySubject<void>();
Expand Down Expand Up @@ -161,15 +160,8 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
protected readonly destroyed = new ReplaySubject<void>();

constructor(
protected readonly editEventDispatcher: EditEventDispatcher,
protected readonly elementRef: ElementRef,
protected readonly focusTrapFactory: FocusTrapFactory,
protected readonly ngZone: NgZone,
protected readonly overlay: Overlay,
protected readonly positionFactory: PopoverEditPositionStrategyFactory,
protected readonly scrollDispatcher: ScrollDispatcher,
protected readonly viewContainerRef: ViewContainerRef,
protected readonly viewportRuler: ViewportRuler) {}
protected readonly services: EditServices, protected readonly elementRef: ElementRef,
protected readonly viewContainerRef: ViewContainerRef) {}

ngAfterViewInit(): void {
this._startListeningToEditEvents();
Expand All @@ -185,18 +177,18 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
}

protected initFocusTrap(): void {
this.focusTrap = this.focusTrapFactory.create(this.overlayRef!.overlayElement);
this.focusTrap = this.services.focusTrapFactory.create(this.overlayRef!.overlayElement);
}

protected closeEditOverlay(): void {
this.editEventDispatcher.doneEditingCell(this.elementRef.nativeElement!);
this.services.editEventDispatcher.doneEditingCell(this.elementRef.nativeElement!);
}

private _startListeningToEditEvents(): void {
this.editEventDispatcher.editingCell(this.elementRef.nativeElement!)
this.services.editEventDispatcher.editingCell(this.elementRef.nativeElement!)
.pipe(takeUntil(this.destroyed))
.subscribe((open) => {
this.ngZone.run(() => {
this.services.ngZone.run(() => {
if (open && this.template) {
if (!this.overlayRef) {
this._createEditOverlay();
Expand All @@ -209,15 +201,15 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
this.overlayRef.detach();
}
});
});
});
}

private _createEditOverlay(): void {
this.overlayRef = this.overlay.create({
this.overlayRef = this.services.overlay.create({
disposeOnNavigation: true,
panelClass: EDIT_PANE_CLASS,
positionStrategy: this._getPositionStrategy(),
scrollStrategy: this.overlay.scrollStrategies.reposition(),
scrollStrategy: this.services.overlay.scrollStrategies.reposition(),
});

this.initFocusTrap();
Expand All @@ -235,7 +227,7 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {

// Update the size of the popup initially and on subsequent changes to
// scroll position and viewport size.
merge(this.scrollDispatcher.scrolled(), this.viewportRuler.change())
merge(this.services.scrollDispatcher.scrolled(), this.services.viewportRuler.change())
.pipe(
startWith(null),
takeUntil(this.overlayRef!.detachments()),
Expand All @@ -262,11 +254,12 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
}

private _getPositionStrategy(): PositionStrategy {
return this.positionFactory.positionStrategyForCells(this._getOverlayCells());
return this.services.positionFactory.positionStrategyForCells(this._getOverlayCells());
}

private _updateOverlaySize(): void {
this.overlayRef!.updateSize(this.positionFactory.sizeConfigForCells(this._getOverlayCells()));
this.overlayRef!.updateSize(
this.services.positionFactory.sizeConfigForCells(this._getOverlayCells()));
}

private _maybeReturnFocusToCell(): void {
Expand Down Expand Up @@ -294,38 +287,20 @@ export class CdkPopoverEditTabOut<C> extends CdkPopoverEdit<C> {
protected focusTrap?: FocusEscapeNotifier;

constructor(
editEventDispatcher: EditEventDispatcher,
elementRef: ElementRef,
focusTrapFactory: FocusTrapFactory,
ngZone: NgZone,
overlay: Overlay,
positionFactory: PopoverEditPositionStrategyFactory,
scrollDispatcher: ScrollDispatcher,
viewContainerRef: ViewContainerRef,
viewportRuler: ViewportRuler,
protected readonly focusEscapeNotifierFactory: FocusEscapeNotifierFactory,
protected readonly focusDispatcher: FocusDispatcher) {
super(
editEventDispatcher,
elementRef,
focusTrapFactory,
ngZone,
overlay,
positionFactory,
scrollDispatcher,
viewContainerRef,
viewportRuler);
elementRef: ElementRef, viewContainerRef: ViewContainerRef, services: EditServices,
protected readonly focusEscapeNotifierFactory: FocusEscapeNotifierFactory) {
super(services, elementRef, viewContainerRef);
}

protected initFocusTrap(): void {
this.focusTrap = this.focusEscapeNotifierFactory.create(this.overlayRef!.overlayElement);

this.focusTrap.escapes().pipe(takeUntil(this.destroyed)).subscribe(direction => {
if (this.editEventDispatcher.editRef) {
this.editEventDispatcher.editRef.blur();
if (this.services.editEventDispatcher.editRef) {
this.services.editEventDispatcher.editRef.blur();
}

this.focusDispatcher.moveFocusHorizontally(
this.services.focusDispatcher.moveFocusHorizontally(
closest(this.elementRef.nativeElement!, CELL_SELECTOR) as HTMLElement,
direction === FocusEscapeNotifierDirection.START ? -1 : 1);

Expand Down Expand Up @@ -358,12 +333,9 @@ export class CdkRowHoverContent implements AfterViewInit, OnDestroy {
protected viewRef: EmbeddedViewRef<any>|null = null;

constructor(
protected readonly elementRef: ElementRef,
protected readonly editEventDispatcher: EditEventDispatcher,
protected readonly ngZone: NgZone,
protected readonly services: EditServices, protected readonly elementRef: ElementRef,
protected readonly templateRef: TemplateRef<any>,
protected readonly viewContainerRef: ViewContainerRef
) {}
protected readonly viewContainerRef: ViewContainerRef) {}

ngAfterViewInit(): void {
this._listenForHoverEvents();
Expand All @@ -379,10 +351,10 @@ export class CdkRowHoverContent implements AfterViewInit, OnDestroy {
}

private _listenForHoverEvents(): void {
this.editEventDispatcher.hoveringOnRow(this.elementRef.nativeElement!)
this.services.editEventDispatcher.hoveringOnRow(this.elementRef.nativeElement!)
.pipe(takeUntil(this.destroyed))
.subscribe(isHovering => {
this.ngZone.run(() => {
this.services.ngZone.run(() => {
if (isHovering) {
if (!this.viewRef) {
// Not doing any positioning in CDK version. Material version
Expand Down