Skip to content

Commit d671487

Browse files
authored
Move focus on key to util class & add force focus option (#16)
1 parent c08a8fc commit d671487

File tree

4 files changed

+60
-11
lines changed

4 files changed

+60
-11
lines changed

projects/angular-components/src/lib/search/search.component.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import {
99
Input,
1010
OnDestroy,
1111
OnInit,
12+
AfterViewInit,
1213
ViewChild,
1314
} from '@angular/core';
1415
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
1516
import { IconMagnifierComponent } from '../icons/icon-magnifier/icon-magnifier.component';
1617
import { debounceTime, noop, Subject } from 'rxjs';
1718
import { NgClass } from '@angular/common';
19+
import { FocusOnKeyUtil } from '../utils/focus-on-key.util';
1820

1921
export const SEARCH_CONTROL_VALUE_ACCESSOR = {
2022
provide: NG_VALUE_ACCESSOR,
@@ -31,9 +33,10 @@ export const SEARCH_CONTROL_VALUE_ACCESSOR = {
3133
changeDetection: ChangeDetectionStrategy.OnPush,
3234
providers: [SEARCH_CONTROL_VALUE_ACCESSOR],
3335
})
34-
export class SearchComponent implements OnInit, OnDestroy, ControlValueAccessor {
36+
export class SearchComponent implements OnInit, AfterViewInit, OnDestroy, ControlValueAccessor {
3537
@Input() placeholder: string = 'Search...';
3638
@Input() focusKey: string = '/';
39+
@Input({ transform: booleanAttribute }) forceFocus: boolean = false;
3740
@Input({ transform: booleanAttribute }) focusKeyEnabled: boolean = true;
3841
@Input({ transform: booleanAttribute }) slim: boolean = false;
3942
@ViewChild('input') _inputElement!: ElementRef<HTMLInputElement>;
@@ -43,6 +46,12 @@ export class SearchComponent implements OnInit, OnDestroy, ControlValueAccessor
4346

4447
private _value: string = '';
4548
private _disabled: boolean = false;
49+
private focusKeyUtil = new FocusOnKeyUtil({
50+
key: '/',
51+
ctrl: false,
52+
shift: false,
53+
force: false,
54+
});
4655

4756
@Input()
4857
get value(): string {
@@ -70,17 +79,24 @@ export class SearchComponent implements OnInit, OnDestroy, ControlValueAccessor
7079
this.value = value;
7180
this._onChange(value);
7281
});
82+
this.focusKeyUtil.updateConfig({
83+
key: this.focusKey,
84+
force: this.forceFocus,
85+
});
86+
}
7387

88+
ngAfterViewInit(): void {
7489
if (this.focusKeyEnabled) {
75-
window.addEventListener('keyup', this._onKeyEvent.bind(this), true);
90+
this.focusKeyUtil.setFocusElement(this._inputElement.nativeElement);
91+
this.focusKeyUtil.enable();
7692
}
7793
}
7894

7995
ngOnDestroy(): void {
8096
this.searchSubject.complete();
8197

8298
if (this.focusKeyEnabled) {
83-
window.removeEventListener('keyup', this._onKeyEvent, true);
99+
this.focusKeyUtil?.disable();
84100
}
85101
}
86102

@@ -114,11 +130,4 @@ export class SearchComponent implements OnInit, OnDestroy, ControlValueAccessor
114130
protected _onInteractionEvent(event: Event): void {
115131
event.stopPropagation();
116132
}
117-
118-
protected _onKeyEvent(event: KeyboardEvent): void {
119-
if (event.key === this.focusKey) {
120-
this._inputElement.nativeElement.focus();
121-
event.preventDefault();
122-
}
123-
}
124133
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export type FocusOnKeyConfig = {
2+
key: string;
3+
ctrl: boolean;
4+
shift: boolean;
5+
force: boolean;
6+
};
7+
8+
export class FocusOnKeyUtil {
9+
constructor(
10+
private config: FocusOnKeyConfig = { key: 'k', ctrl: true, shift: false, force: false },
11+
private focusElement?: HTMLElement,
12+
) {}
13+
14+
setFocusElement(focusElement: HTMLElement): void {
15+
this.focusElement = focusElement;
16+
}
17+
18+
updateConfig(config: Partial<FocusOnKeyConfig>): void {
19+
this.config = { ...this.config, ...config };
20+
}
21+
22+
enable(): void {
23+
if (!this.focusElement) console.warn('No focus element set');
24+
window.addEventListener(this.config.force ? 'keydown' : 'keyup', this._onKeyEvent.bind(this));
25+
}
26+
27+
disable(): void {
28+
window.removeEventListener('keydown', this._onKeyEvent);
29+
window.removeEventListener('keyup', this._onKeyEvent);
30+
}
31+
32+
private _onKeyEvent(event: KeyboardEvent): void {
33+
if (!this.focusElement) return;
34+
if (event.key === this.config.key) {
35+
this.focusElement.focus();
36+
event.preventDefault();
37+
}
38+
}
39+
}

projects/angular-components/src/public_api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ export * from './lib/datatable/dt-content.directive';
1212

1313
// helper classes
1414
export * from './lib/icons/icon-base';
15+
export * from './lib/utils/focus-on-key.util';

src/app/app.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ <h2>Checkbox</h2>
2424
<li>
2525
<h2>Search</h2>
2626
<div class="components">
27-
<ff-search [(ngModel)]="searchText" style="width: 100%"></ff-search>
27+
<ff-search [(ngModel)]="searchText" style="width: 100%" forceFocus></ff-search>
2828
<div class="separator">
2929
<ff-search placeholder="Test the focus key" focusKey="=" style="width: 100%"></ff-search>
3030
<ff-search placeholder="Disabled" style="width: 100%" disabled></ff-search>

0 commit comments

Comments
 (0)