src/app/shared/components/tag-input/tag-input.component.ts
selector | crm-tag-input |
styleUrls | tag-input.component.scss |
templateUrl | ./tag-input.component.html |
Properties |
|
Methods |
|
Inputs |
Outputs |
HostBindings |
addOnBlur
|
Type:
Default value: |
addOnEnter
|
Type:
Default value: |
addOnPaste
|
Type:
Default value: |
allowedTagsPattern
|
Type:
Default value: |
delimiterCode
|
Type:
Default value: |
errorMessage
|
Default value: |
items
|
Type:
Default value: |
pasteDelimiter
|
Type:
Default value: |
placeholder
|
Type:
Default value: |
readonly
|
Type:
Default value: |
itemsChange
|
$event type: EventEmitter
|
class.crm-tag-input-focus |
class.crm-tag-input-focus:
|
Private _addTags | ||||||||
_addTags(tags: string[])
|
||||||||
Parameters :
Returns :
void
|
Private _handleBackspace |
_handleBackspace()
|
Returns :
void
|
Private _isTagValid | ||||||||
_isTagValid(tagString: string)
|
||||||||
Parameters :
Returns :
any
|
Private _removeTag | ||||||||
_removeTag(tagIndexToRemove: )
|
||||||||
Parameters :
Returns :
void
|
Private _resetInput |
_resetInput()
|
Returns :
void
|
Private _resetSelected |
_resetSelected()
|
Returns :
void
|
Private _splitString | ||||||||
_splitString(tagString: string)
|
||||||||
Parameters :
Returns :
any
|
inputBlurred | ||||||||
inputBlurred(event: )
|
||||||||
Parameters :
Returns :
void
|
inputChanged | ||||||||
inputChanged(event: )
|
||||||||
Parameters :
Returns :
void
|
inputFocused | ||||||||
inputFocused(event: )
|
||||||||
Parameters :
Returns :
void
|
inputPaste | ||||||||
inputPaste(event: )
|
||||||||
Parameters :
Returns :
void
|
isBlank | ||||||||
isBlank(obj: any)
|
||||||||
Parameters :
Returns :
boolean
|
isValid |
isValid()
|
Returns :
boolean
|
Private isValidAndNotInTagList | ||||||||
isValidAndNotInTagList(tagString: string)
|
||||||||
Parameters :
Returns :
boolean
|
ngAfterViewInit |
ngAfterViewInit()
|
Returns :
void
|
ngOnChanges | ||||||||
ngOnChanges(changes: SimpleChanges)
|
||||||||
Parameters :
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
registerOnChange | ||||||||
registerOnChange(fn: any)
|
||||||||
Parameters :
Returns :
void
|
registerOnTouched | ||||||||
registerOnTouched(fn: any)
|
||||||||
Parameters :
Returns :
void
|
Private splitPasteString | ||||||||
splitPasteString(tagString: string)
|
||||||||
Parameters :
Returns :
any
|
Private uniqueTags | ||||||||
uniqueTags(tags: string[])
|
||||||||
Parameters :
Returns :
any
|
writeValue | ||||||||
writeValue(value: any)
|
||||||||
Parameters :
Returns :
void
|
Public delimiter |
delimiter:
|
Type : number
|
Public inputValue |
inputValue:
|
Type : string
|
Default value : ''
|
onChange |
onChange:
|
Type : function
|
Default value : () => {
this.itemsChange.emit(this.tagsList);
}
|
Implemented as part of ControlValueAccessor. |
onTouched |
onTouched:
|
Type : function
|
Default value : () => {
}
|
Public selectedTag |
selectedTag:
|
Type : number
|
Public tagsList |
tagsList:
|
Type : string[]
|
import {Component, Input, HostBinding, Output, EventEmitter, OnInit, OnChanges, SimpleChanges} from "@angular/core";
@Component({
selector: 'crm-tag-input',
templateUrl: './tag-input.component.html',
styleUrls: ['./tag-input.component.scss']
})
export class TagInputComponent implements OnInit, OnChanges {
@Input() placeholder: string = 'Add a tag';
@Input() items: string[] = [];
@Output() itemsChange = new EventEmitter<string[]>();
@Input() delimiterCode: number = 32;
@Input() pasteDelimiter: RegExp = null;
@Input() addOnBlur: boolean = true;
@Input() addOnEnter: boolean = true;
@Input() addOnPaste: boolean = true;
@Input() allowedTagsPattern: RegExp = /.+/;
@Input() errorMessage = "Invalid email";
@HostBinding('class.crm-tag-input-focus') isFocussed;
@Input() readonly: boolean = false;
public tagsList: string[];
public inputValue: string = '';
public delimiter: number;
public selectedTag: number;
ngOnInit() {
this.tagsList = this.items;
this.onChange(this.tagsList);
this.delimiter = this.delimiterCode;
}
ngOnChanges(changes: SimpleChanges) {
if(changes['items']) {
this.tagsList = this.items
}
}
ngAfterViewInit() {
// If the user passes an undefined variable to items this will warn
// and set the value to an empty array
if (!this.tagsList) {
console.warn('TagInputComponent was passed an undefined value in items. Please make sure the variable is defined.');
this.tagsList = [];
this.onChange(this.tagsList);
}
}
inputChanged(event) {
let key = event.keyCode;
switch (key) {
case 8: // Backspace
this._handleBackspace();
break;
case 13: //Enter
this.addOnEnter && this._addTags([this.inputValue]);
event.preventDefault();
break;
case this.delimiter:
this._addTags([this.inputValue]);
event.preventDefault();
break;
default:
this._resetSelected();
break;
}
}
inputBlurred(event) {
this.addOnBlur && this._addTags([this.inputValue]);
this.isFocussed = false;
}
inputFocused(event) {
this.isFocussed = true;
}
inputPaste(event) {
let clipboardData = event.clipboardData || (event.originalEvent && event.originalEvent.clipboardData);
let pastedString = clipboardData.getData('text/plain');
let tags = this.splitPasteString(pastedString);
let tagsToAdd = tags.filter((tag) => this.isValidAndNotInTagList(tag));
let filteredTagsToAdd = this.uniqueTags(tagsToAdd);
this._addTags(filteredTagsToAdd);
setTimeout(() => this.inputValue = '', 50);
}
private _splitString(tagString: string) {
tagString = tagString.trim();
let tags = tagString.split(String.fromCharCode(this.delimiter));
return tags.filter((tag) => !!tag);
}
private splitPasteString(tagString: string) {
tagString = tagString.trim();
let tags = this.pasteDelimiter ? tagString.split(this.pasteDelimiter) : tagString.split(/\s\n|\n\s|\s|\n/);
return tags.filter((tag) => !!tag.trim());
}
private _isTagValid(tagString: string) {
return this.allowedTagsPattern.test(tagString);
}
private isValidAndNotInTagList(tagString: string) {
return this.allowedTagsPattern.test(tagString) && !this.tagsList.find(tag => tag === tagString);
}
private uniqueTags(tags: string[]) {
return tags.filter((tag, index, array) => index == array.indexOf(tag));
}
private _addTags(tags: string[]) {
let validTags = tags.filter((tag) => this._isTagValid(tag));
this.tagsList = this.tagsList.concat(validTags);
this._resetSelected();
this._resetInput();
this.onChange(this.tagsList);
}
private _removeTag(tagIndexToRemove) {
this.tagsList.splice(tagIndexToRemove, 1);
this._resetSelected();
this.onChange(this.tagsList);
}
private _handleBackspace() {
if (!this.inputValue.length && this.tagsList.length) {
if (!this.isBlank(this.selectedTag)) {
this._removeTag(this.selectedTag);
}
else {
this.selectedTag = this.tagsList.length - 1;
}
}
}
private _resetSelected() {
this.selectedTag = null;
}
private _resetInput() {
this.inputValue = '';
}
/** Implemented as part of ControlValueAccessor. */
onChange: (value) => any = () => {
this.itemsChange.emit(this.tagsList);
};
onTouched: () => any = () => {
};
writeValue(value: any) {
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
isValid() {
return this.inputValue && !this._isTagValid(this.inputValue);
}
isBlank(obj: any): boolean {
return obj == null;
}
}
<crm-tag-input-item
[text]="tag"
[index]="index"
[selected]="selectedTag === index"
(tagRemoved)="_removeTag($event)"
[readonly]="readonly"
*ngFor="let tag of tagsList; let index = index">
</crm-tag-input-item>
<input
class="form-control"
type="text"
autocomplete="off"
[placeholder]="placeholder"
[(ngModel)]="inputValue"
(paste)="inputPaste($event)"
(keydown)="inputChanged($event)"
(blur)="inputBlurred($event)"
(focus)="inputFocused()"
*ngIf="!readonly">
<div class="form-error" *ngIf="isValid()">
{{errorMessage}}
</div>