diff --git a/projects/common/src/fm/components/tag-input/tag-input.component.html b/projects/common/src/fm/components/tag-input/tag-input.component.html index 99ce84b..1eade61 100644 --- a/projects/common/src/fm/components/tag-input/tag-input.component.html +++ b/projects/common/src/fm/components/tag-input/tag-input.component.html @@ -1,3 +1,11 @@ -
- {{tag}} -
+
+ {{tag}} +
diff --git a/projects/common/src/fm/components/tag-input/tag-input.component.ts b/projects/common/src/fm/components/tag-input/tag-input.component.ts index 5be11dc..102cfbe 100644 --- a/projects/common/src/fm/components/tag-input/tag-input.component.ts +++ b/projects/common/src/fm/components/tag-input/tag-input.component.ts @@ -1,104 +1,122 @@ -import { Component, Input, forwardRef,ElementRef,ViewChild } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR,NgModel } from '@angular/forms'; -import { Observable,of } from 'rxjs'; -import { tap,catchError,debounceTime,distinctUntilChanged,switchMap } from 'rxjs/operators' -import { TypeaheadService } from '../../services/typeahead.service'; - -@Component({ - selector: 'fm-tag-input', - templateUrl: 'tag-input.component.html', - styleUrls: ['tag-input.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => TagInputComponent), - multi: true - } - ] -}) - -export class TagInputComponent implements ControlValueAccessor { - @Input() tags: string[] - @ViewChild('taginput', { static: true }) tagInputElement: ElementRef; - public tag: string; - searching = false; - searchFailed = false; - - constructor(private typeaheadService: TypeaheadService) { - } - - tagExists(tag) { - if (tag.length == 0) return true; - for (let t of this.tags) { - if (t.toLowerCase() == tag.toLowerCase()) return true; - } - return false; - } - - handleDeleteTag(tag) { - let tags = []; - for (let t of this.tags) { - if (t != tag) tags.push(t); - } - this.tags = tags; - this.propagateChange(tags); - } - - handleAddTag(event) { - if (!this.tagExists(this.tag)) { - this.tags.push(this.tag); - this.propagateChange(this.tags); - } - this.tag = ""; - this.tagInputElement.nativeElement.focus(); - } - - handleCheckAddTag(event: KeyboardEvent) { - if (event.keyCode == 188) { - let tag = this.tag.substr(0, this.tag.length - 1); // strip , - if (!this.tagExists(tag)) { - this.tags.push(tag); - this.propagateChange(this.tags); - } - this.tag = ""; - } - } - - handleSelect(event) { - if (!this.tagExists(event.item)) { - this.tags.push(event.item); - this.propagateChange(this.tags); - } - event.preventDefault(); - this.tag = ""; - } - - propagateChange = (_: any) => { }; - - registerOnChange(fn) { - this.propagateChange = fn; - } - - findTag = (text$: Observable) => - text$.pipe( - debounceTime(200), - distinctUntilChanged(), - tap(() => this.searching = true), - switchMap(term => term.length < 1 ? of([]) : - this.typeaheadService.getTagTypeaheadItems(term).pipe( - tap(() => this.searchFailed = false), - catchError(() => { - this.searchFailed = true; - return of([]); - })) - ), - tap(() => this.searching = false) - ); - - writeValue(value: any) { - this.tags = value; - this.tag = ""; - } - - registerOnTouched() { } -} +import {Component, ElementRef, forwardRef, Input, ViewChild} from '@angular/core'; +import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; +import {Observable, of} from 'rxjs'; +import {catchError, debounceTime, distinctUntilChanged, switchMap, tap} from 'rxjs/operators'; +import {TypeaheadService} from '@farmmaps/common'; +import {NgbTypeahead} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'fm-tag-input', + templateUrl: 'tag-input.component.html', + styleUrls: ['tag-input.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TagInputComponent), + multi: true + } + ] +}) + +export class TagInputComponent implements ControlValueAccessor { + @Input() tags: string[] = []; + @ViewChild('tagInputElement', {static: true}) tagInputElement: ElementRef; + @ViewChild(NgbTypeahead, {static: true}) typeahead: NgbTypeahead; + + public tag: string; + searching = false; + searchFailed = false; + + constructor(private typeaheadService: TypeaheadService) { + } + + tagExists(tag) { + if (tag.length === 0) { + return true; + } + for (const t of this.tags) { + if (t.toLowerCase() === tag.toLowerCase()) { + return true; + } + } + return false; + } + + addTag(tag, keepFocus = true) { + if (!this.tagExists(tag)) { + this.tags.push(tag); + this.propagateChange(this.tags); + } + this.tag = ''; + + if (keepFocus) { + this.tagInputElement.nativeElement.focus(); + } + } + + handleDeleteTag(tag) { + const tags = []; + for (const t of this.tags) { + if (t !== tag) { + tags.push(t); + } + } + this.tags = tags; + this.propagateChange(tags); + } + + handleBlur(event, keepFocus = true) { + if (!this.typeahead.isPopupOpen()) { + this.addTag(this.tag, keepFocus); + } else { + this.tag = ''; + } + } + + handleKeyUp(event: KeyboardEvent) { + if (event.keyCode === 188) { + const tag = this.tag.substr(0, this.tag.length - 1); // strip , + this.addTag(tag); + } + } + + handleSelect(event) { + if (!this.tagExists(event.item)) { + this.tags.push(event.item); + this.propagateChange(this.tags); + } + event.preventDefault(); + this.tag = ''; + } + + propagateChange = (_: any) => { + } + + registerOnChange(fn) { + this.propagateChange = fn; + } + + findTag = (text$: Observable) => + text$.pipe( + distinctUntilChanged(), + debounceTime(200), + tap(() => this.searching = true), + switchMap(term => term.length < 1 ? of([]) : + this.typeaheadService.getTagTypeaheadItems(term).pipe( + tap(() => this.searchFailed = false), + catchError(() => { + this.searchFailed = true; + return of([]); + })) + ), + tap(() => this.searching = false) + ) + + writeValue(value: any) { + this.tags = value; + this.tag = ''; + } + + registerOnTouched() { + } +}