/
tag-input.directive.ts
111 lines (97 loc) · 2.96 KB
/
tag-input.directive.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
import {
AfterViewInit,
Directive,
ElementRef,
EventEmitter,
HostBinding,
HostListener,
Input,
NgZone,
Output,
Renderer2,
} from '@angular/core';
import { Subject } from 'rxjs';
import { filter, map, takeUntil } from 'rxjs/operators';
import { NbStatusService } from '../../services/status.service';
import { NbFocusMonitor } from '../cdk/a11y/a11y.module';
import { ENTER } from '../cdk/keycodes/keycodes';
import { NbFormFieldControl } from '../form-field/form-field-control';
import { NbInputDirective } from '../input/input.directive';
export interface NbTagInputAddEvent {
input: ElementRef<HTMLInputElement>;
value: string;
}
/**
*
* `[nbTagInput]` directive connects input with a `nb-tag-list` component.
*
* @stacked-example(Tag Input, tag/tag-input.component)
*
* @additional-example(Tag Input with Autocomplete, tag/tag-input-with-autocomplete.component)
*
* @styles
*
* tag-list-tiny-tag-offset:
* tag-list-small-tag-offset:
* tag-list-medium-tag-offset:
* tag-list-large-tag-offset:
* tag-list-giant-tag-offset:
* tag-list-with-input-tiny-padding:
* tag-list-with-input-small-padding:
* tag-list-with-input-medium-padding:
* tag-list-with-input-large-padding:
* tag-list-with-input-giant-padding:
*/
@Directive({
selector: 'input[nbTagInput]',
exportAs: 'nbTagInput',
providers: [
{ provide: NbFormFieldControl, useExisting: NbTagInputDirective },
],
})
export class NbTagInputDirective extends NbInputDirective implements AfterViewInit {
protected readonly keyDown$: Subject<KeyboardEvent> = new Subject<KeyboardEvent>();
get _value(): string {
return this._hostElement.nativeElement.value;
}
/**
* Controls which keys should trigger tag add event.
*/
@Input() separatorKeys: number[] = [ENTER];
/**
* Emits when a tag need to be added.
*/
@Output() tagAdd: EventEmitter<NbTagInputAddEvent> = new EventEmitter<NbTagInputAddEvent>();
@HostBinding('class.nb-tag-input') readonly nbTagInputClass = true;
@HostListener('keydown', ['$event'])
_onKeydown(event: KeyboardEvent): void {
this.keyDown$.next(event);
}
constructor(
public _hostElement: ElementRef<HTMLInputElement>,
protected focusMonitor: NbFocusMonitor,
protected renderer: Renderer2,
protected zone: NgZone,
protected statusService: NbStatusService,
) {
super(_hostElement, focusMonitor, renderer, zone, statusService);
}
ngAfterViewInit() {
super.ngAfterViewInit();
this.keyDown$
.pipe(
filter(({ keyCode }: KeyboardEvent) => this.isSeparatorKey(keyCode)),
map(() => this._value),
takeUntil(this.destroy$),
)
.subscribe((value: string) => this.tagAdd.emit({ value, input: this._hostElement }));
}
protected isSeparatorKey(keyCode: number): boolean {
return this.separatorKeys.includes(keyCode);
}
}