diff --git a/projects/angular/clarity.api.md b/projects/angular/clarity.api.md index d62af93f1a..332e060e39 100644 --- a/projects/angular/clarity.api.md +++ b/projects/angular/clarity.api.md @@ -4923,7 +4923,7 @@ export const CUSTOM_BUTTON_TYPES: any; // // @public (undocumented) export class DatagridNumericFilter extends DatagridFilterRegistrar> implements CustomFilter, AfterViewInit { - constructor(filters: FiltersProvider, domAdapter: DomAdapter, commonStrings: ClrCommonStringsService, popoverToggleService: ClrPopoverToggleService); + constructor(filters: FiltersProvider, domAdapter: DomAdapter, commonStrings: ClrCommonStringsService, popoverToggleService: ClrPopoverToggleService, ngZone: NgZone); // (undocumented) commonStrings: ClrCommonStringsService; set customNumericFilter(value: ClrDatagridNumericFilterInterface | RegisteredFilter>); diff --git a/projects/angular/src/data/datagrid/built-in/filters/datagrid-numeric-filter.spec.ts b/projects/angular/src/data/datagrid/built-in/filters/datagrid-numeric-filter.spec.ts index 11fd902723..66d920bedf 100644 --- a/projects/angular/src/data/datagrid/built-in/filters/datagrid-numeric-filter.spec.ts +++ b/projects/angular/src/data/datagrid/built-in/filters/datagrid-numeric-filter.spec.ts @@ -104,7 +104,8 @@ export default function (): void { const input: HTMLInputElement = document.querySelector("input[type='number']"); spyOn(input, 'focus'); expect(input.focus).not.toHaveBeenCalled(); - tick(); + // The `requestAnimationFrame` is mocked through `setTimeout(fn, 16)`. + tick(16); expect(input.focus).toHaveBeenCalled(); })); diff --git a/projects/angular/src/data/datagrid/built-in/filters/datagrid-numeric-filter.ts b/projects/angular/src/data/datagrid/built-in/filters/datagrid-numeric-filter.ts index b7ebc0be9b..8e52fefa2e 100644 --- a/projects/angular/src/data/datagrid/built-in/filters/datagrid-numeric-filter.ts +++ b/projects/angular/src/data/datagrid/built-in/filters/datagrid-numeric-filter.ts @@ -4,7 +4,7 @@ * The full license information can be found in LICENSE in the root directory of this project. */ -import { AfterViewInit, Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, EventEmitter, Input, NgZone, Output, ViewChild } from '@angular/core'; import { Subscription } from 'rxjs'; import { ClrDatagridFilter } from '../../datagrid-filter'; @@ -52,7 +52,8 @@ export class DatagridNumericFilter filters: FiltersProvider, private domAdapter: DomAdapter, public commonStrings: ClrCommonStringsService, - private popoverToggleService: ClrPopoverToggleService + private popoverToggleService: ClrPopoverToggleService, + private ngZone: NgZone ) { super(filters); } @@ -104,9 +105,16 @@ export class DatagridNumericFilter this.subscriptions.push( this.popoverToggleService.openChange.subscribe(openChange => { this.open = openChange; - // The timeout in used because when this executes, the input isn't displayed. - setTimeout(() => { - this.domAdapter.focus(this.input.nativeElement); + // Note: this is being run outside of the Angular zone because `element.focus()` doesn't require + // running change detection. + this.ngZone.runOutsideAngular(() => { + // The animation frame in used because when this executes, the input isn't displayed. + // Note: `element.focus()` causes re-layout and this may lead to frame drop on slower devices. + // `setTimeout` is a macrotask and macrotasks are executed within the current rendering frame. + // Animation tasks are executed within the next rendering frame. + requestAnimationFrame(() => { + this.domAdapter.focus(this.input.nativeElement); + }); }); }) );