sp-combo
Version:
# Angular sp-combo - Multiselect, Multiline and Autocomplete
875 lines • 118 kB
JavaScript
import { Component, forwardRef, ChangeDetectorRef, Input, Output, EventEmitter, ContentChild, TemplateRef, ViewEncapsulation, HostListener, HostBinding, ViewChild, ElementRef, ChangeDetectionStrategy, Inject, ContentChildren, InjectionToken, Attribute } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { takeUntil, startWith, tap, debounceTime, map, filter } from 'rxjs/operators';
import { Subject, merge } from 'rxjs';
import { NgOptionTemplateDirective, NgLabelTemplateDirective, NgHeaderTemplateDirective, NgFooterTemplateDirective, NgOptgroupTemplateDirective, NgNotFoundTemplateDirective, NgTypeToSearchTemplateDirective, NgLoadingTextTemplateDirective, NgMultiLabelTemplateDirective, NgTagTemplateDirective, NgLoadingSpinnerTemplateDirective } from './sp-templates.directive';
import { ConsoleService } from './console.service';
import { isDefined, isFunction, isPromise, isObject } from './value-utils';
import { ItemsList } from './items-list';
import { KeyCode } from './sp-select.types';
import { newId } from './id';
import { NgDropdownPanelComponent } from './ng-dropdown-panel.component';
import { NgOptionComponent } from './ng-option.component';
import { SpSelectConfig } from './config.service';
import { NgDropdownPanelService } from './ng-dropdown-panel.service';
export const SELECTION_MODEL_FACTORY = new InjectionToken('ng-select-selection-model');
export class SpSelectComponent {
constructor(classes, autoFocus, config, newSelectionModel, _elementRef, _cd, _console) {
this.classes = classes;
this.autoFocus = autoFocus;
this._cd = _cd;
this._console = _console;
this.markFirst = true;
this.dropdownPosition = 'auto';
this.loading = false;
this.closeOnSelect = true;
this.hideSelected = false;
this.selectOnTab = false;
this.bufferAmount = 4;
this.selectableGroup = false;
this.selectableGroupAsModel = true;
this.searchFn = null;
this.trackByFn = null;
this.clearOnBackspace = true;
this.labelForId = null;
this.inputAttrs = {};
this.readonly = false;
this.searchWhileComposing = true;
this.minTermLength = 0;
this.editableSearchTerm = false;
this.keyDownFn = (_) => true;
this.multiple = false;
this.addTag = false;
this.searchable = true;
this.clearable = true;
this.isOpen = false;
// output events
this.blurEvent = new EventEmitter();
this.focusEvent = new EventEmitter();
this.changeEvent = new EventEmitter();
this.openEvent = new EventEmitter();
this.closeEvent = new EventEmitter();
this.searchEvent = new EventEmitter();
this.clearEvent = new EventEmitter();
this.addEvent = new EventEmitter();
this.removeEvent = new EventEmitter();
this.scroll = new EventEmitter();
this.scrollToEnd = new EventEmitter();
this.viewPortItems = [];
this.searchTerm = null;
this.dropdownId = newId();
this.escapeHTML = true;
this.useDefaultClass = true;
this._items = [];
this._defaultLabel = 'label';
this._pressedKeys = [];
this._isComposing = false;
this._destroy$ = new Subject();
this._keyPress$ = new Subject();
this._onChange = (_) => { };
this._onTouched = () => { };
this.extraLbl = [];
this.extraVal = [];
this.clearItem = (item) => {
const option = this.selectedItems.find(x => x.value === item);
this.unselect(option);
};
this.trackByOption = (_, item) => {
if (this.trackByFn) {
return this.trackByFn(item.value);
}
return item;
};
this._mergeGlobalConfig(config);
this.itemsList = new ItemsList(this, newSelectionModel());
this.element = _elementRef.nativeElement;
}
get items() { return this._items; }
;
set items(value) {
this._itemsAreUsed = true;
this._items = value;
}
;
get compareWith() { return this._compareWith; }
set compareWith(fn) {
if (!isFunction(fn)) {
throw Error('`compareWith` must be a function.');
}
this._compareWith = fn;
}
get clearSearchOnAdd() { return isDefined(this._clearSearchOnAdd) ? this._clearSearchOnAdd : this.closeOnSelect; }
;
set clearSearchOnAdd(value) {
this._clearSearchOnAdd = value;
}
;
get disabled() { return this.readonly || this._disabled; }
;
get filtered() { return (!!this.searchTerm && this.searchable || this._isComposing); }
;
get _editableSearchTerm() {
return this.editableSearchTerm && !this.multiple;
}
get selectedItems() {
return this.itemsList.selectedItems;
}
get selectedValues() {
return this.selectedItems.map(x => x.value);
}
get hasValue() {
return this.selectedItems.length > 0;
}
get currentPanelPosition() {
if (this.dropdownPanel) {
return this.dropdownPanel.currentPosition;
}
return undefined;
}
getExtraValue(item, idx) {
if (this.extraVal.length > idx) {
var ef = this.extraVal[idx].split(".");
var val = item;
var id = 0;
for (var a of ef) {
val = val[a];
id += 1;
if (id == ef.length) {
return val;
}
}
}
else {
return item;
}
}
ngOnInit() {
this._handleKeyPresses();
this._setInputAttributes();
if (this.extraValues)
this.extraVal = this.extraValues.split(",");
if (this.extraLables)
this.extraLbl = this.extraLables.split(",");
}
ngOnChanges(changes) {
if (changes.multiple) {
this.itemsList.clearSelected();
}
if (changes.items) {
this._setItems(changes.items.currentValue || []);
}
if (changes.isOpen) {
this._manualOpen = isDefined(changes.isOpen.currentValue);
}
}
ngAfterViewInit() {
if (!this._itemsAreUsed) {
this.escapeHTML = false;
this._setItemsFromNgOptions();
}
if (isDefined(this.autoFocus)) {
this.focus();
}
}
ngOnDestroy() {
this._destroy$.next();
this._destroy$.complete();
}
handleKeyDown($event) {
const keyCode = KeyCode[$event.which];
if (keyCode) {
if (this.keyDownFn($event) === false) {
return;
}
this.handleKeyCode($event);
}
else if ($event.key && $event.key.length === 1) {
this._keyPress$.next($event.key.toLocaleLowerCase());
}
}
handleKeyCode($event) {
switch ($event.which) {
case KeyCode.ArrowDown:
this._handleArrowDown($event);
break;
case KeyCode.ArrowUp:
this._handleArrowUp($event);
break;
case KeyCode.Space:
this._handleSpace($event);
break;
case KeyCode.Enter:
this._handleEnter($event);
break;
case KeyCode.Tab:
this._handleTab($event);
break;
case KeyCode.Esc:
this.close();
$event.preventDefault();
break;
case KeyCode.Backspace:
this._handleBackspace();
break;
}
}
handleMousedown($event) {
const target = $event.target;
if (target.tagName !== 'INPUT') {
$event.preventDefault();
}
if (target.classList.contains('ng-clear-wrapper')) {
this.handleClearClick();
return;
}
if (target.classList.contains('ng-arrow-wrapper')) {
this.handleArrowClick();
return;
}
if (target.classList.contains('ng-value-icon')) {
return;
}
if (!this.focused) {
this.focus();
}
if (this.searchable) {
this.open();
}
else {
this.toggle();
}
}
handleArrowClick() {
if (this.isOpen) {
this.close();
}
else {
this.open();
}
}
handleClearClick() {
if (this.hasValue) {
this.itemsList.clearSelected(true);
this._updateNgModel();
}
this._clearSearch();
this.focus();
this.clearEvent.emit();
this._onSelectionChanged();
}
clearModel() {
if (!this.clearable) {
return;
}
this.itemsList.clearSelected();
this._updateNgModel();
}
writeValue(value) {
this.itemsList.clearSelected();
this._handleWriteValue(value);
this._cd.markForCheck();
}
registerOnChange(fn) {
this._onChange = fn;
}
registerOnTouched(fn) {
this._onTouched = fn;
}
setDisabledState(state) {
this._disabled = state;
this._cd.markForCheck();
}
toggle() {
if (!this.isOpen) {
this.open();
}
else {
this.close();
}
}
open() {
if (this.disabled || this.isOpen || this.itemsList.maxItemsSelected || this._manualOpen) {
return;
}
if (!this._isTypeahead && !this.addTag && this.itemsList.noItemsToSelect) {
return;
}
this.isOpen = true;
this.itemsList.markSelectedOrDefault(this.markFirst);
this.openEvent.emit();
if (!this.searchTerm) {
this.focus();
}
this.detectChanges();
}
close() {
if (!this.isOpen || this._manualOpen) {
return;
}
this.isOpen = false;
if (!this._editableSearchTerm) {
this._clearSearch();
}
else {
this.itemsList.resetFilteredItems();
}
this.itemsList.unmarkItem();
this._onTouched();
this.closeEvent.emit();
this._cd.markForCheck();
}
toggleItem(item) {
if (!item || item.disabled || this.disabled) {
return;
}
if (this.multiple && item.selected) {
this.unselect(item);
}
else {
this.select(item);
}
if (this._editableSearchTerm) {
this._setSearchTermFromItems();
}
this._onSelectionChanged();
}
select(item) {
if (!item.selected) {
this.itemsList.select(item);
if (this.clearSearchOnAdd && !this._editableSearchTerm) {
this._clearSearch();
}
this._updateNgModel();
if (this.multiple) {
this.addEvent.emit(item.value);
}
}
if (this.closeOnSelect || this.itemsList.noItemsToSelect) {
this.close();
}
}
focus() {
this.searchInput.nativeElement.focus();
}
blur() {
this.searchInput.nativeElement.blur();
}
unselect(item) {
if (!item) {
return;
}
this.itemsList.unselect(item);
this.focus();
this._updateNgModel();
this.removeEvent.emit(item);
}
selectTag() {
let tag;
if (isFunction(this.addTag)) {
tag = this.addTag(this.searchTerm);
}
else {
tag = this._primitive ? this.searchTerm : { [this.bindLabel]: this.searchTerm };
}
const handleTag = (item) => this._isTypeahead || !this.isOpen ? this.itemsList.mapItem(item, null) : this.itemsList.addItem(item);
if (isPromise(tag)) {
tag.then(item => this.select(handleTag(item))).catch(() => { });
}
else if (tag) {
this.select(handleTag(tag));
}
}
showClear() {
return this.clearable && (this.hasValue || this.searchTerm) && !this.disabled;
}
get showAddTag() {
if (!this._validTerm) {
return false;
}
const term = this.searchTerm.toLowerCase().trim();
return this.addTag &&
(!this.itemsList.filteredItems.some(x => x.label.toLowerCase() === term) &&
(!this.hideSelected && this.isOpen || !this.selectedItems.some(x => x.label.toLowerCase() === term))) &&
!this.loading;
}
showNoItemsFound() {
const empty = this.itemsList.filteredItems.length === 0;
return ((empty && !this._isTypeahead && !this.loading) ||
(empty && this._isTypeahead && this._validTerm && !this.loading)) &&
!this.showAddTag;
}
showTypeToSearch() {
const empty = this.itemsList.filteredItems.length === 0;
return empty && this._isTypeahead && !this._validTerm && !this.loading;
}
onCompositionStart() {
this._isComposing = true;
}
onCompositionEnd(term) {
this._isComposing = false;
if (this.searchWhileComposing) {
return;
}
this.filter(term);
}
filter(term) {
if (this._isComposing && !this.searchWhileComposing) {
return;
}
this.searchTerm = term;
if (this._isTypeahead && (this._validTerm || this.minTermLength === 0)) {
this.typeahead.next(term);
}
if (!this._isTypeahead) {
this.itemsList.filter(this.searchTerm);
if (this.isOpen) {
this.itemsList.markSelectedOrDefault(this.markFirst);
}
}
this.searchEvent.emit({ term, items: this.itemsList.filteredItems.map(x => x.value) });
this.open();
}
onInputFocus($event) {
if (this.focused) {
return;
}
if (this._editableSearchTerm) {
this._setSearchTermFromItems();
}
this.element.classList.add('ng-select-focused');
this.focusEvent.emit($event);
this.focused = true;
}
onInputBlur($event) {
this.element.classList.remove('ng-select-focused');
this.blurEvent.emit($event);
if (!this.isOpen && !this.disabled) {
this._onTouched();
}
if (this._editableSearchTerm) {
this._setSearchTermFromItems();
}
this.focused = false;
}
onItemHover(item) {
if (item.disabled) {
return;
}
this.itemsList.markItem(item);
}
detectChanges() {
if (!this._cd.destroyed) {
this._cd.detectChanges();
}
}
_setSearchTermFromItems() {
const selected = this.selectedItems && this.selectedItems[0];
this.searchTerm = (selected && selected.label) || null;
}
_setItems(items) {
const firstItem = items[0];
this.bindLabel = this.bindLabel || this._defaultLabel;
this._primitive = isDefined(firstItem) ? !isObject(firstItem) : this._primitive || this.bindLabel === this._defaultLabel;
this.itemsList.setItems(items);
if (items.length > 0 && this.hasValue) {
this.itemsList.mapSelectedItems();
}
if (this.isOpen && isDefined(this.searchTerm) && !this._isTypeahead) {
this.itemsList.filter(this.searchTerm);
}
if (this._isTypeahead || this.isOpen) {
this.itemsList.markSelectedOrDefault(this.markFirst);
}
}
_setItemsFromNgOptions() {
const mapNgOptions = (options) => {
this.items = options.map(option => ({
$ngOptionValue: option.value,
$ngOptionLabel: option.elementRef.nativeElement.innerHTML,
disabled: option.disabled
}));
this.itemsList.setItems(this.items);
if (this.hasValue) {
this.itemsList.mapSelectedItems();
}
this.detectChanges();
};
const handleOptionChange = () => {
const changedOrDestroyed = merge(this.ngOptions.changes, this._destroy$);
merge(...this.ngOptions.map(option => option.stateChange$))
.pipe(takeUntil(changedOrDestroyed))
.subscribe(option => {
const item = this.itemsList.findItem(option.value);
item.disabled = option.disabled;
item.label = option.label || item.label;
this._cd.detectChanges();
});
};
this.ngOptions.changes
.pipe(startWith(this.ngOptions), takeUntil(this._destroy$))
.subscribe(options => {
this.bindLabel = this._defaultLabel;
mapNgOptions(options);
handleOptionChange();
});
}
_isValidWriteValue(value) {
if (!isDefined(value) || (this.multiple && value === '') || Array.isArray(value) && value.length === 0) {
return false;
}
const validateBinding = (item) => {
if (!isDefined(this.compareWith) && isObject(item) && this.bindValue) {
this._console.warn(`Binding object(${JSON.stringify(item)}) with bindValue is not allowed.`);
return false;
}
return true;
};
if (this.multiple) {
if (!Array.isArray(value)) {
this._console.warn('Multiple select ngModel should be array.');
return false;
}
return value.every(item => validateBinding(item));
}
else {
return validateBinding(value);
}
}
_handleWriteValue(ngModel) {
if (!this._isValidWriteValue(ngModel)) {
return;
}
const select = (val) => {
let item = this.itemsList.findItem(val);
if (item) {
this.itemsList.select(item);
}
else {
const isValObject = isObject(val);
const isPrimitive = !isValObject && !this.bindValue;
if ((isValObject || isPrimitive)) {
this.itemsList.select(this.itemsList.mapItem(val, null));
}
else if (this.bindValue) {
item = {
[this.bindLabel]: null,
[this.bindValue]: val
};
this.itemsList.select(this.itemsList.mapItem(item, null));
}
}
};
if (this.multiple) {
ngModel.forEach(item => select(item));
}
else {
select(ngModel);
}
}
_handleKeyPresses() {
if (this.searchable) {
return;
}
this._keyPress$
.pipe(takeUntil(this._destroy$), tap(letter => this._pressedKeys.push(letter)), debounceTime(200), filter(() => this._pressedKeys.length > 0), map(() => this._pressedKeys.join('')))
.subscribe(term => {
const item = this.itemsList.findByLabel(term);
if (item) {
if (this.isOpen) {
this.itemsList.markItem(item);
this._cd.markForCheck();
}
else {
this.select(item);
}
}
this._pressedKeys = [];
});
}
_setInputAttributes() {
const input = this.searchInput.nativeElement;
const attributes = Object.assign({ type: 'text', autocorrect: 'off', autocapitalize: 'off', autocomplete: this.labelForId ? 'off' : this.dropdownId }, this.inputAttrs);
for (const key of Object.keys(attributes)) {
input.setAttribute(key, attributes[key]);
}
}
_updateNgModel() {
const model = [];
for (const item of this.selectedItems) {
if (this.bindValue) {
let value = null;
if (item.children) {
const groupKey = this.groupValue ? this.bindValue : this.groupBy;
value = item.value[groupKey || this.groupBy];
}
else {
value = this.itemsList.resolveNested(item.value, this.bindValue);
}
model.push(value);
}
else {
model.push(item.value);
}
}
const selected = this.selectedItems.map(x => x.value);
if (this.multiple) {
this._onChange(model);
this.changeEvent.emit(selected);
}
else {
this._onChange(isDefined(model[0]) ? model[0] : null);
this.changeEvent.emit(selected[0]);
}
this._cd.markForCheck();
}
_clearSearch() {
if (!this.searchTerm) {
return;
}
this._changeSearch(null);
this.itemsList.resetFilteredItems();
}
_changeSearch(searchTerm) {
this.searchTerm = searchTerm;
if (this._isTypeahead) {
this.typeahead.next(searchTerm);
}
}
_scrollToMarked() {
if (!this.isOpen || !this.dropdownPanel) {
return;
}
this.dropdownPanel.scrollTo(this.itemsList.markedItem);
}
_scrollToTag() {
if (!this.isOpen || !this.dropdownPanel) {
return;
}
this.dropdownPanel.scrollToTag();
}
_onSelectionChanged() {
if (this.isOpen && this.multiple && this.appendTo) {
// Make sure items are rendered.
this._cd.detectChanges();
this.dropdownPanel.adjustPosition();
}
}
_handleTab($event) {
if (this.isOpen === false && !this.addTag) {
return;
}
if (this.selectOnTab) {
if (this.itemsList.markedItem) {
this.toggleItem(this.itemsList.markedItem);
$event.preventDefault();
}
else if (this.showAddTag) {
this.selectTag();
$event.preventDefault();
}
else {
this.close();
}
}
else {
this.close();
}
}
_handleEnter($event) {
if (this.isOpen || this._manualOpen) {
if (this.itemsList.markedItem) {
this.toggleItem(this.itemsList.markedItem);
}
else if (this.showAddTag) {
this.selectTag();
}
}
else if (this.openOnEnter) {
this.open();
}
else {
return;
}
$event.preventDefault();
}
_handleSpace($event) {
if (this.isOpen || this._manualOpen) {
return;
}
this.open();
$event.preventDefault();
}
_handleArrowDown($event) {
if (this._nextItemIsTag(+1)) {
this.itemsList.unmarkItem();
this._scrollToTag();
}
else {
this.itemsList.markNextItem();
this._scrollToMarked();
}
this.open();
$event.preventDefault();
}
_handleArrowUp($event) {
if (!this.isOpen) {
return;
}
if (this._nextItemIsTag(-1)) {
this.itemsList.unmarkItem();
this._scrollToTag();
}
else {
this.itemsList.markPreviousItem();
this._scrollToMarked();
}
$event.preventDefault();
}
_nextItemIsTag(nextStep) {
const nextIndex = this.itemsList.markedIndex + nextStep;
return this.addTag && this.searchTerm
&& this.itemsList.markedItem
&& (nextIndex < 0 || nextIndex === this.itemsList.filteredItems.length);
}
_handleBackspace() {
if (this.searchTerm || !this.clearable || !this.clearOnBackspace || !this.hasValue) {
return;
}
if (this.multiple) {
this.unselect(this.itemsList.lastSelectedItem);
}
else {
this.clearModel();
}
}
get _isTypeahead() {
return this.typeahead && this.typeahead.observers.length > 0;
}
get _validTerm() {
const term = this.searchTerm && this.searchTerm.trim();
return term && term.length >= this.minTermLength;
}
_mergeGlobalConfig(config) {
this.placeholder = this.placeholder || config.placeholder;
this.notFoundText = this.notFoundText || config.notFoundText;
this.typeToSearchText = this.typeToSearchText || config.typeToSearchText;
this.addTagText = this.addTagText || config.addTagText;
this.loadingText = this.loadingText || config.loadingText;
this.clearAllText = this.clearAllText || config.clearAllText;
this.virtualScroll = isDefined(this.virtualScroll)
? this.virtualScroll
: isDefined(config.disableVirtualScroll) ? !config.disableVirtualScroll : false;
this.openOnEnter = isDefined(this.openOnEnter) ? this.openOnEnter : config.openOnEnter;
this.appendTo = this.appendTo || config.appendTo;
this.bindValue = this.bindValue || config.bindValue;
this.appearance = this.appearance || config.appearance;
}
}
SpSelectComponent.decorators = [
{ type: Component, args: [{
selector: 'sp-select',
template: "<div (mousedown)=\"handleMousedown($event)\" [class.ng-appearance-outline]=\"appearance === 'outline'\"\r\n [class.ng-has-value]=\"hasValue\" class=\"ng-select-container\">\r\n\r\n <div class=\"ng-value-container\">\r\n <div class=\"ng-placeholder\">{{placeholder}}</div>\r\n\r\n <ng-container *ngIf=\"!multiLabelTemplate && selectedItems.length > 0\">\r\n <div [class.ng-value-disabled]=\"item.disabled\" class=\"ng-value\"\r\n *ngFor=\"let item of selectedItems; trackBy: trackByOption\">\r\n <ng-template #defaultLabelTemplate>\r\n <span class=\"ng-value-icon left\" (click)=\"unselect(item);\" aria-hidden=\"true\">\u00D7</span>\r\n <span class=\"ng-value-label\" [ngItemLabel]=\"item.label\" [escape]=\"escapeHTML\"></span>\r\n </ng-template>\r\n\r\n <ng-template [ngTemplateOutlet]=\"labelTemplate || defaultLabelTemplate\"\r\n [ngTemplateOutletContext]=\"{ item: item.value, clear: clearItem, label: item.label }\">\r\n </ng-template>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template *ngIf=\"multiLabelTemplate && selectedValues.length > 0\" [ngTemplateOutlet]=\"multiLabelTemplate\"\r\n [ngTemplateOutletContext]=\"{ items: selectedValues, clear: clearItem }\">\r\n </ng-template>\r\n\r\n <div class=\"ng-input\">\r\n <input #searchInput [attr.id]=\"labelForId\" [attr.tabindex]=\"tabIndex\"\r\n [readOnly]=\"!searchable || itemsList.maxItemsSelected\" [disabled]=\"disabled\"\r\n [value]=\"searchTerm ? searchTerm : ''\" (input)=\"filter(searchInput.value)\"\r\n (compositionstart)=\"onCompositionStart()\" (compositionend)=\"onCompositionEnd(searchInput.value)\"\r\n (focus)=\"onInputFocus($event)\" (blur)=\"onInputBlur($event)\" (change)=\"$event.stopPropagation()\"\r\n role=\"combobox\" [attr.aria-expanded]=\"isOpen\" [attr.aria-owns]=\"isOpen ? dropdownId : null\"\r\n [attr.aria-activedescendant]=\"isOpen ? itemsList?.markedItem?.htmlId : null\">\r\n </div>\r\n </div>\r\n\r\n <ng-container *ngIf=\"loading\">\r\n <ng-template #defaultLoadingSpinnerTemplate>\r\n <div class=\"ng-spinner-loader\"></div>\r\n </ng-template>\r\n\r\n <ng-template [ngTemplateOutlet]=\"loadingSpinnerTemplate || defaultLoadingSpinnerTemplate\">\r\n </ng-template>\r\n </ng-container>\r\n\r\n <span *ngIf=\"showClear()\" class=\"ng-clear-wrapper\" title=\"{{clearAllText}}\">\r\n <span class=\"ng-clear\" aria-hidden=\"true\">\u00D7</span>\r\n </span>\r\n\r\n <span class=\"ng-arrow-wrapper\">\r\n <span class=\"ng-arrow\"></span>\r\n </span>\r\n</div>\r\n\r\n<ng-dropdown-panel *ngIf=\"isOpen\" class=\"ng-dropdown-panel\" [virtualScroll]=\"virtualScroll\"\r\n [bufferAmount]=\"bufferAmount\" [appendTo]=\"appendTo\" [position]=\"dropdownPosition\" [headerTemplate]=\"headerTemplate\"\r\n [footerTemplate]=\"footerTemplate\" [filterValue]=\"searchTerm\" [items]=\"itemsList.filteredItems\"\r\n [markedItem]=\"itemsList.markedItem\" (update)=\"viewPortItems = $event\" (scroll)=\"scroll.emit($event)\"\r\n (scrollToEnd)=\"scrollToEnd.emit($event)\" (outsideClick)=\"close()\" [class.ng-select-multiple]=\"multiple\"\r\n [ngClass]=\"appendTo ? classes : null\" [id]=\"dropdownId\">\r\n\r\n <ng-container>\r\n <div class=\"ng-option\" [attr.role]=\"item.children ? 'group' : 'option'\" (click)=\"toggleItem(item)\"\r\n (mouseover)=\"onItemHover(item)\" *ngFor=\"let item of viewPortItems; trackBy: trackByOption\"\r\n [class.ng-option-disabled]=\"item.disabled\" [class.ng-option-selected]=\"item.selected\"\r\n [class.ng-optgroup]=\"item.children\" [class.ng-option]=\"!item.children\"\r\n [class.ng-option-child]=\"!!item.parent\" [class.ng-option-marked]=\"item === itemsList.markedItem\"\r\n [attr.aria-selected]=\"item.selected\" [attr.id]=\"item?.htmlId\">\r\n\r\n <ng-template #defaultOptionTemplate>\r\n <span class=\"ng-option-label\" [ngItemLabel]=\"item.label\" [escape]=\"escapeHTML\"></span>\r\n\r\n </ng-template>\r\n\r\n <ng-template\r\n [ngTemplateOutlet]=\"item.children ? (optgroupTemplate || defaultOptionTemplate) : (optionTemplate || defaultOptionTemplate)\"\r\n [ngTemplateOutletContext]=\"{ item: item.value, item$:item, index: item.index, searchTerm: searchTerm }\">\r\n </ng-template>\r\n </div>\r\n\r\n <div class=\"ng-option\" [class.ng-option-marked]=\"!itemsList.markedItem\" (mouseover)=\"itemsList.unmarkItem()\"\r\n role=\"option\" (click)=\"selectTag()\" *ngIf=\"showAddTag\">\r\n <ng-template #defaultTagTemplate>\r\n <span><span class=\"ng-tag-label\">{{addTagText}}</span>\"{{searchTerm}}\"</span>\r\n </ng-template>\r\n\r\n <ng-template [ngTemplateOutlet]=\"tagTemplate || defaultTagTemplate\"\r\n [ngTemplateOutletContext]=\"{ searchTerm: searchTerm }\">\r\n </ng-template>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"showNoItemsFound()\">\r\n <ng-template #defaultNotFoundTemplate>\r\n <div class=\"ng-option ng-option-disabled\">{{notFoundText}}</div>\r\n </ng-template>\r\n\r\n <ng-template [ngTemplateOutlet]=\"notFoundTemplate || defaultNotFoundTemplate\"\r\n [ngTemplateOutletContext]=\"{ searchTerm: searchTerm }\">\r\n </ng-template>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"showTypeToSearch()\">\r\n <ng-template #defaultTypeToSearchTemplate>\r\n <div class=\"ng-option ng-option-disabled\">{{typeToSearchText}}</div>\r\n </ng-template>\r\n\r\n <ng-template [ngTemplateOutlet]=\"typeToSearchTemplate || defaultTypeToSearchTemplate\">\r\n </ng-template>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"loading && itemsList.filteredItems.length === 0\">\r\n <ng-template #defaultLoadingTextTemplate>\r\n <div class=\"ng-option ng-option-disabled\">{{loadingText}}</div>\r\n </ng-template>\r\n\r\n <ng-template [ngTemplateOutlet]=\"loadingTextTemplate || defaultLoadingTextTemplate\"\r\n [ngTemplateOutletContext]=\"{ searchTerm: searchTerm }\">\r\n </ng-template>\r\n </ng-container>\r\n\r\n</ng-dropdown-panel>",
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SpSelectComponent),
multi: true
},
NgDropdownPanelService
],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
'role': 'listbox',
'[class.ng-select]': 'useDefaultClass',
'[class.ng-select-single]': '!multiple',
},
styles: [".ng-select{display:block;position:relative}.ng-select,.ng-select div,.ng-select input,.ng-select span{box-sizing:border-box}.ng-select [hidden]{display:none}.ng-select.ng-select-searchable .ng-select-container .ng-value-container .ng-input{opacity:1}.ng-select.ng-select-opened .ng-select-container{z-index:1001}.ng-select.ng-select-disabled .ng-select-container .ng-value-container .ng-placeholder,.ng-select.ng-select-disabled .ng-select-container .ng-value-container .ng-value{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;cursor:default;user-select:none}.ng-select.ng-select-disabled .ng-arrow-wrapper{cursor:default}.ng-select.ng-select-filtered .ng-placeholder{display:none}.ng-select .ng-select-container{cursor:default;display:flex;outline:none;overflow:hidden;position:relative;width:100%}.ng-select .ng-select-container .ng-value-container{display:flex;flex:1}.ng-select .ng-select-container .ng-value-container .ng-input{opacity:0}.ng-select .ng-select-container .ng-value-container .ng-input>input{background:none transparent;border:0;box-shadow:none;box-sizing:content-box;cursor:default;outline:none;width:100%}.ng-select .ng-select-container .ng-value-container .ng-input>input::-ms-clear{display:none}.ng-select .ng-select-container .ng-value-container .ng-input>input[readonly]{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;padding:0;user-select:none;width:0}.ng-select.ng-select-single.ng-select-filtered .ng-select-container .ng-value-container .ng-value{visibility:hidden}.ng-select.ng-select-single .ng-select-container .ng-value-container,.ng-select.ng-select-single .ng-select-container .ng-value-container .ng-value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ng-select.ng-select-single .ng-select-container .ng-value-container .ng-value .ng-value-icon{display:none}.ng-select.ng-select-single .ng-select-container .ng-value-container .ng-input{left:0;position:absolute;width:100%}.ng-select.ng-select-multiple.ng-select-disabled>.ng-select-container .ng-value-container .ng-value .ng-value-icon{display:none}.ng-select.ng-select-multiple .ng-select-container .ng-value-container{flex-wrap:wrap}.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-placeholder{position:absolute}.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value{white-space:nowrap}.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value.ng-value-disabled .ng-value-icon{display:none}.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon{cursor:pointer}.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-input{flex:1;z-index:2}.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-placeholder{z-index:1}.ng-select .ng-clear-wrapper{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;cursor:pointer;position:relative;user-select:none;width:17px}.ng-select .ng-clear-wrapper .ng-clear{display:inline-block;font-size:18px;line-height:1;pointer-events:none}.ng-select .ng-spinner-loader{-webkit-animation:load8 .8s linear infinite;animation:load8 .8s linear infinite;border:2px solid rgba(66,66,66,.2);border-left-color:#424242;border-radius:50%;font-size:10px;height:17px;margin-right:5px;position:relative;text-indent:-9999em;transform:translateZ(0);width:17px}.ng-select .ng-spinner-loader:after{border-radius:50%;height:17px;width:17px}@-webkit-keyframes load8{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes load8{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.ng-select .ng-arrow-wrapper{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;cursor:pointer;position:relative;text-align:center;user-select:none}.ng-select .ng-arrow-wrapper .ng-arrow{display:inline-block;height:0;pointer-events:none;position:relative;width:0}.ng-dropdown-panel{-webkit-overflow-scrolling:touch;box-sizing:border-box;opacity:0;position:absolute;width:100%;z-index:1050}.ng-dropdown-panel .ng-dropdown-panel-items{box-sizing:border-box;display:block;height:auto;max-height:240px;overflow-y:auto}.ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup,.ng-dropdown-panel .ng-dropdown-panel-items .ng-option{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ng-dropdown-panel .ng-dropdown-panel-items .ng-option{box-sizing:border-box;cursor:pointer;display:block}.ng-dropdown-panel .ng-dropdown-panel-items .ng-option .highlighted{font-weight:700;text-decoration:underline}.ng-dropdown-panel .ng-dropdown-panel-items .ng-option.disabled{cursor:default}.ng-dropdown-panel .scroll-host{-webkit-overflow-scrolling:touch;display:block;overflow:hidden;overflow-y:auto;position:relative}.ng-dropdown-panel .scrollable-content{height:100%;left:0;position:absolute;top:0;width:100%}.ng-dropdown-panel .total-padding{opacity:0;width:1px}"]
},] }
];
SpSelectComponent.ctorParameters = () => [
{ type: String, decorators: [{ type: Attribute, args: ['class',] }] },
{ type: undefined, decorators: [{ type: Attribute, args: ['autofocus',] }] },
{ type: SpSelectConfig },
{ type: undefined, decorators: [{ type: Inject, args: [SELECTION_MODEL_FACTORY,] }] },
{ type: ElementRef },
{ type: ChangeDetectorRef },
{ type: ConsoleService }
];
SpSelectComponent.propDecorators = {
bindLabel: [{ type: Input }],
bindValue: [{ type: Input }],
markFirst: [{ type: Input }],
placeholder: [{ type: Input }],
notFoundText: [{ type: Input }],
typeToSearchText: [{ type: Input }],
addTagText: [{ type: Input }],
loadingText: [{ type: Input }],
clearAllText: [{ type: Input }],
appearance: [{ type: Input }],
dropdownPosition: [{ type: Input }],
appendTo: [{ type: Input }],
loading: [{ type: Input }],
closeOnSelect: [{ type: Input }],
hideSelected: [{ type: Input }],
selectOnTab: [{ type: Input }],
openOnEnter: [{ type: Input }],
maxSelectedItems: [{ type: Input }],
groupBy: [{ type: Input }],
groupValue: [{ type: Input }],
bufferAmount: [{ type: Input }],
virtualScroll: [{ type: Input }],
selectableGroup: [{ type: Input }],
selectableGroupAsModel: [{ type: Input }],
searchFn: [{ type: Input }],
trackByFn: [{ type: Input }],
clearOnBackspace: [{ type: Input }],
labelForId: [{ type: Input }],
inputAttrs: [{ type: Input }],
tabIndex: [{ type: Input }],
readonly: [{ type: Input }],
searchWhileComposing: [{ type: Input }],
minTermLength: [{ type: Input }],
editableSearchTerm: [{ type: Input }],
keyDownFn: [{ type: Input }],
typeahead: [{ type: Input }, { type: HostBinding, args: ['class.ng-select-typeahead',] }],
multiple: [{ type: Input }, { type: HostBinding, args: ['class.ng-select-multiple',] }],
addTag: [{ type: Input }, { type: HostBinding, args: ['class.ng-select-taggable',] }],
searchable: [{ type: Input }, { type: HostBinding, args: ['class.ng-select-searchable',] }],
clearable: [{ type: Input }, { type: HostBinding, args: ['class.ng-select-clearable',] }],
isOpen: [{ type: Input }, { type: HostBinding, args: ['class.ng-select-opened',] }],
items: [{ type: Input }],
compareWith: [{ type: Input }],
clearSearchOnAdd: [{ type: Input }],
extraLables: [{ type: Input }],
extraValues: [{ type: Input }],
blurEvent: [{ type: Output, args: ['blur',] }],
focusEvent: [{ type: Output, args: ['focus',] }],
changeEvent: [{ type: Output, args: ['change',] }],
openEvent: [{ type: Output, args: ['open',] }],
closeEvent: [{ type: Output, args: ['close',] }],
searchEvent: [{ type: Output, args: ['search',] }],
clearEvent: [{ type: Output, args: ['clear',] }],
addEvent: [{ type: Output, args: ['add',] }],
removeEvent: [{ type: Output, args: ['remove',] }],
scroll: [{ type: Output, args: ['scroll',] }],
scrollToEnd: [{ type: Output, args: ['scrollToEnd',] }],
optionTemplate: [{ type: ContentChild, args: [NgOptionTemplateDirective, { read: TemplateRef },] }],
optgroupTemplate: [{ type: ContentChild, args: [NgOptgroupTemplateDirective, { read: TemplateRef },] }],
labelTemplate: [{ type: ContentChild, args: [NgLabelTemplateDirective, { read: TemplateRef },] }],
multiLabelTemplate: [{ type: ContentChild, args: [NgMultiLabelTemplateDirective, { read: TemplateRef },] }],
headerTemplate: [{ type: ContentChild, args: [NgHeaderTemplateDirective, { read: TemplateRef },] }],
footerTemplate: [{ type: ContentChild, args: [NgFooterTemplateDirective, { read: TemplateRef },] }],
notFoundTemplate: [{ type: ContentChild, args: [NgNotFoundTemplateDirective, { read: TemplateRef },] }],
typeToSearchTemplate: [{ type: ContentChild, args: [NgTypeToSearchTemplateDirective, { read: TemplateRef },] }],
loadingTextTemplate: [{ type: ContentChild, args: [NgLoadingTextTemplateDirective, { read: TemplateRef },] }],
tagTemplate: [{ type: ContentChild, args: [NgTagTemplateDirective, { read: TemplateRef },] }],
loadingSpinnerTemplate: [{ type: ContentChild, args: [NgLoadingSpinnerTemplateDirective, { read: TemplateRef },] }],
dropdownPanel: [{ type: ViewChild, args: [forwardRef(() => NgDropdownPanelComponent),] }],
searchInput: [{ type: ViewChild, args: ['searchInput', { static: true },] }],
ngOptions: [{ type: ContentChildren, args: [NgOptionComponent, { descendants: true },] }],
disabled: [{ type: HostBinding, args: ['class.ng-select-disabled',] }],
filtered: [{ type: HostBinding, args: ['class.ng-select-filtered',] }],
handleKeyDown: [{ type: HostListener, args: ['keydown', ['$event'],] }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Atc2VsZWN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJHOi9Qcm9qZWN0cy9QYXRpbCBMaWJyYXJ5L3BhdGlsLWxpYnJhcnkvcHJvamVjdHMvc3AtY29tYm8vc3JjLyIsInNvdXJjZXMiOlsic3Atc2VsZWN0L2xpYi9zcC1zZWxlY3QuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBSVQsVUFBVSxFQUNWLGlCQUFpQixFQUNqQixLQUFLLEVBQ0wsTUFBTSxFQUNOLFlBQVksRUFDWixZQUFZLEVBQ1osV0FBVyxFQUNYLGlCQUFpQixFQUNqQixZQUFZLEVBQ1osV0FBVyxFQUNYLFNBQVMsRUFDVCxVQUFVLEVBQ1YsdUJBQXVCLEVBQ3ZCLE1BQU0sRUFFTixlQUFlLEVBRWYsY0FBYyxFQUNkLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQXdCLGlCQUFpQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDekUsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEYsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFHdEMsT0FBTyxFQUNMLHlCQUF5QixFQUN6Qix3QkFBd0IsRUFDeEIseUJBQXlCLEVBQ3pCLHlCQUF5QixFQUN6QiwyQkFBMkIsRUFDM0IsMkJBQTJCLEVBQzNCLCtCQUErQixFQUMvQiw4QkFBOEIsRUFDOUIsNkJBQTZCLEVBQzdCLHNCQUFzQixFQUN0QixpQ0FBaUMsRUFDbEMsTUFBTSwwQkFBMEIsQ0FBQztBQUVsQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMz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