ngx-select2-ex
Version:
Angular(2+) version of the popular alternative to select inputs, Select2. Select2 classes are used in the template, so you can use any pre-existing styles for Select2 and it will look the same as the original.
1,374 lines (1,358 loc) • 43.4 kB
JavaScript
import { Injectable, Component, Input, forwardRef, Pipe, HostBinding, ApplicationRef, ComponentFactoryResolver, Injector, Directive, ElementRef, HostListener, Renderer2, NgModule } from '@angular/core';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExOption {
/**
* @param {?} id
* @param {?} value
* @param {?=} disabled
* @param {?=} selected
*/
constructor(id, value, disabled, selected) {
this.id = id;
this.value = value;
this.disabled = !!disabled;
this.selected = !!selected;
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExOptionHandler extends NgxSelect2ExOption {
/**
* @param {?} id
* @param {?} value
* @param {?=} disabled
* @param {?=} selected
* @param {?=} highlighted
*/
constructor(id, value, disabled, selected, highlighted) {
super(id, value, !!disabled, !!selected);
this.highlighted = !!highlighted;
}
/**
* @param {?} optionHandler
* @return {?}
*/
static copy(optionHandler) {
return new NgxSelect2ExOptionHandler(optionHandler.id, optionHandler.value, optionHandler.disabled, optionHandler.selected, optionHandler.highlighted);
}
/**
* @param {?} arrayOfOptionHandlers
* @return {?}
*/
static copyArray(arrayOfOptionHandlers) {
const /** @type {?} */ options = arrayOfOptionHandlers.map((option) => NgxSelect2ExOptionHandler.copy(option));
return [...options];
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExLanguageInputs {
/**
* @param {?=} languageInputs
*/
constructor(languageInputs) {
this.errorLoading = languageInputs && languageInputs.errorLoading ?
languageInputs.errorLoading : () => `The results could not be loaded.`;
this.inputTooLong = languageInputs && languageInputs.inputTooLong ?
languageInputs.inputTooLong : (n) => `Please delete ${n} character`;
this.inputTooShort = languageInputs && languageInputs.inputTooShort ?
languageInputs.inputTooShort : (n) => `Please enter ${n} or more characters`;
this.loadingMore = languageInputs && languageInputs.loadingMore ?
languageInputs.loadingMore : () => `Loading more results…`;
this.maximumSelected = languageInputs && languageInputs.maximumSelected ?
languageInputs.maximumSelected : (n) => `You can only select ${n} item`;
this.noResults = languageInputs && languageInputs.noResults ?
languageInputs.noResults : () => `No results found`;
this.searching = languageInputs && languageInputs.searching ?
languageInputs.searching : () => `Searching…`;
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExService {
constructor() {
this.multi = null;
this.disabled = false;
this.theme = 'default';
this.minimumResultsForSearch = 0;
this.minimumInputLength = null;
this.maximumInputLength = null;
this.language = new NgxSelect2ExLanguageInputs();
this.selectOnClose = false;
this.closeOnSelect = true;
this._options = new BehaviorSubject([]);
this._dropdownPosition = new ReplaySubject(1);
this._isOpen = new BehaviorSubject(false);
this._isInFocus = new BehaviorSubject(false);
this._selection = new BehaviorSubject([]);
this._search = new BehaviorSubject(null);
}
/**
* @return {?}
*/
get options() {
return this._options.getValue();
}
/**
* @param {?} options
* @return {?}
*/
set options(options) {
this._options.next(NgxSelect2ExOptionHandler.copyArray(options));
this.selection = this.options;
}
/**
* @return {?}
*/
getOptionsAsObservable() {
return this._options.asObservable();
}
/**
* @param {?} options
* @return {?}
*/
set selection(options) {
options = NgxSelect2ExOptionHandler.copyArray(options);
let /** @type {?} */ selection = options.filter((option) => option.selected);
if (this.multi) {
this._selection.next(selection);
}
else {
let /** @type {?} */ selectedOption;
if (selection.length === 0 && options.length) {
selectedOption = NgxSelect2ExOptionHandler.copyArray(options).reverse().pop();
}
else if (selection.length > 0) {
selectedOption = selection.pop();
}
options.forEach(o => o.selected = false);
options[options.findIndex(o => o.id === selectedOption.id)].selected = true;
this._options.next(options);
selection = [selectedOption];
this._selection.next(selection);
}
}
/**
* @return {?}
*/
get selection() {
return this._selection.getValue();
}
/**
* @return {?}
*/
getSelectionAsObservable() {
return this._selection.asObservable();
}
/**
* @param {?} dropdownPosition
* @return {?}
*/
set dropdownPosition(dropdownPosition) {
this._dropdownPosition.next(dropdownPosition);
}
/**
* @return {?}
*/
getDropdownPositionAsObservable() {
return this._dropdownPosition.asObservable();
}
/**
* @param {?} isOpen
* @return {?}
*/
set isOpen(isOpen) {
this._isOpen.next(isOpen);
}
/**
* @return {?}
*/
get isOpen() {
return this._isOpen.getValue();
}
/**
* @return {?}
*/
getIsOpenAsObservable() {
return this._isOpen.asObservable();
}
/**
* @param {?} isInFocus
* @return {?}
*/
set isInFocus(isInFocus) {
this._isInFocus.next(isInFocus);
}
/**
* @return {?}
*/
get isInFocus() {
return this._isInFocus.getValue();
}
/**
* @return {?}
*/
getIsInFocusAsObservable() {
return this._isInFocus.asObservable();
}
/**
* @param {?} search
* @return {?}
*/
set search(search) {
this._search.next(search);
}
/**
* @return {?}
*/
get search() {
return this._search.getValue();
}
/**
* @return {?}
*/
getSearchAsObservable() {
return this._search.asObservable();
}
/**
* @return {?}
*/
open() {
this.isOpen = true;
}
/**
* @return {?}
*/
close() {
this.isOpen = false;
}
/**
* @param {?} optionHandlerToSelect
* @return {?}
*/
select(optionHandlerToSelect) {
if (!this.multi) {
this.options.forEach((option) => option.selected = false);
}
const /** @type {?} */ indexOfSelected = this.options.findIndex((option) => option.id === optionHandlerToSelect.id);
if (indexOfSelected > -1) {
const /** @type {?} */ options = NgxSelect2ExOptionHandler.copyArray(this.options);
options[indexOfSelected].selected = true;
this.options = options;
}
}
/**
* @param {?} optionHandlerToDeselect
* @return {?}
*/
deselect(optionHandlerToDeselect) {
if (!this.multi) {
return;
}
else {
const /** @type {?} */ indexOfDeselected = this.options.findIndex((option) => option.id === optionHandlerToDeselect.id);
if (indexOfDeselected > -1) {
const /** @type {?} */ options = NgxSelect2ExOptionHandler.copyArray(this.options);
options[indexOfDeselected].selected = false;
this.options = options;
}
}
}
/**
* @return {?}
*/
clear() {
const /** @type {?} */ options = NgxSelect2ExOptionHandler.copyArray(this.options);
options.forEach((option) => option.selected = false);
this._options.next(options);
this._selection.next([]);
}
}
NgxSelect2ExService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
NgxSelect2ExService.ctorParameters = () => [];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExComponent {
/**
* @param {?} ngxSelect2ExService
*/
constructor(ngxSelect2ExService) {
this.ngxSelect2ExService = ngxSelect2ExService;
this.options = null;
this.disabled = null;
this.multi = null;
this.theme = null;
this.minimumResultsForSearch = null;
this.minimumInputLength = null;
this.maximumInputLength = null;
this.language = null;
this.selectOnClose = false;
this.closeOnSelect = true;
this.allowClear = false;
this.placeholder = null;
this.selection = [];
this.subscriptions = [];
this.propagateChange = (_) => { };
}
/**
* @param {?} search
* @return {?}
*/
set search(search) {
this.ngxSelect2ExService.search = search;
}
/**
* @return {?}
*/
get search() {
return this.ngxSelect2ExService.search;
}
/**
* @return {?}
*/
ngOnInit() {
this.initStaticInputValues();
this.subscribeToSelection();
this.subscribeToIsOpen();
this.subscribeToIsInFocus();
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (changes['options'] && changes['options'].currentValue.length &&
changes['options'].previousValue !== changes['options'].currentValue) {
this.initOptions(changes['options'].currentValue);
}
if (changes['disabled'] !== undefined &&
changes['disabled'].previousValue !== changes['disabled'].currentValue) {
this.ngxSelect2ExService.disabled = changes['disabled'].currentValue;
}
}
/**
* @return {?}
*/
ngOnDestroy() {
this.unsubscribe();
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
this.initOptions(value);
}
/**
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this.propagateChange = fn;
}
/**
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) { }
/**
* @param {?} isDisabled
* @return {?}
*/
setDisabledState(isDisabled) {
this.disabled = isDisabled;
this.ngxSelect2ExService.disabled = isDisabled;
}
/**
* @return {?}
*/
getContainerThemeClass() {
return 'select2-container--' + this.ngxSelect2ExService.theme;
}
/**
* @return {?}
*/
getStyleOfSearchListItem() {
const /** @type {?} */ width = (!this.selection || !this.selection.length) && this.placeholder ? '100%' : null;
return { 'width': width };
}
/**
* @param {?} search
* @return {?}
*/
getStyleOfInlineInput(search) {
if (!search && (!this.selection || !this.selection.length) && this.placeholder) {
return { 'width': '100%' };
}
const /** @type {?} */ width = search ? `${((search.length + 1) * 0.75)}em` : '0.75em';
return { 'width': width };
}
/**
* @return {?}
*/
getInlineInputPlaceholder() {
return (!this.selection || !this.selection.length) && this.placeholder ? this.placeholder : '';
}
/**
* @return {?}
*/
clearSelection() {
if (this.shouldShowClearSelectionButton() && (!this.multi && this.placeholder || this.multi) && !this.disabled) {
this.ngxSelect2ExService.clear();
}
}
/**
* @return {?}
*/
shouldShowClearSelectionButton() {
return this.allowClear && this.selection && !!this.selection.length;
}
/**
* @return {?}
*/
shouldShowPlaceholder() {
return (!this.selection || !this.selection.length) && !!this.placeholder;
}
/**
* @return {?}
*/
getTitleTooltipText() {
if (this.selection && this.selection.length && this.selection[0].value) {
return this.selection[0].value;
}
else if (this.placeholder) {
return this.placeholder;
}
else {
return '';
}
}
/**
* @param {?} optionHandlerToDeselect
* @return {?}
*/
deselect(optionHandlerToDeselect) {
this.ngxSelect2ExService.deselect(optionHandlerToDeselect);
}
/**
* @return {?}
*/
subscribeToSelection() {
this.subscriptions.push(this.ngxSelect2ExService.getSelectionAsObservable()
.subscribe((selection) => {
this.selection = selection;
this.propagateChange(this.selection);
}));
}
/**
* @return {?}
*/
subscribeToIsOpen() {
this.subscriptions.push(this.ngxSelect2ExService.getIsOpenAsObservable()
.subscribe((isOpen) => this.isOpen = isOpen));
}
/**
* @return {?}
*/
subscribeToIsInFocus() {
this.subscriptions.push(this.ngxSelect2ExService.getIsInFocusAsObservable()
.subscribe((isInFocus) => this.isInFocus = isInFocus));
}
/**
* @param {?} options
* @return {?}
*/
initOptions(options) {
if (this.isStringList(options)) {
this.ngxSelect2ExService.options = options.map((option, index) => new NgxSelect2ExOptionHandler(index, option));
}
else if (this.isOptionInterfaceList(options)) {
this.ngxSelect2ExService.options = options.map((option) => new NgxSelect2ExOptionHandler(option.id, option.value, option.disabled, option.selected));
}
else {
throw new Error('Input for options array should be of type Array<string> or Array<INgxSelect2ExOption>.');
}
}
/**
* @param {?} list
* @return {?}
*/
isStringList(list) {
return list && list.every((item) => {
return typeof item === 'string';
});
}
/**
* @param {?} list
* @return {?}
*/
isOptionInterfaceList(list) {
return list && list.every((item) => {
return 'id' in item && 'value' in item;
});
}
/**
* @param {?} changes
* @param {?} fieldName
* @return {?}
*/
defaultChangeListener(changes, fieldName) {
if (changes[fieldName] && changes[fieldName].previousValue !== changes[fieldName].currentValue) {
this.ngxSelect2ExService[fieldName] = changes[fieldName].currentValue;
}
}
/**
* @return {?}
*/
initStaticInputValues() {
this.defaultInputSetter('multi');
this.defaultInputSetter('theme');
this.defaultInputSetter('minimumResultsForSearch');
this.defaultInputSetter('minimumInputLength');
this.defaultInputSetter('maximumInputLength', this.minimumInputLength && this.maximumInputLength && this.maximumInputLength < this.minimumInputLength ?
this.minimumInputLength :
this.maximumInputLength);
this.defaultInputSetter('language', new NgxSelect2ExLanguageInputs(this.language));
this.defaultInputSetter('selectOnClose');
this.defaultInputSetter('closeOnSelect');
}
/**
* @param {?} inputField
* @param {?=} optionalValue
* @return {?}
*/
defaultInputSetter(inputField, optionalValue) {
if (this[inputField] !== null) {
this.ngxSelect2ExService[inputField] = optionalValue ? optionalValue : this[inputField];
}
}
/**
* @return {?}
*/
unsubscribe() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
}
}
NgxSelect2ExComponent.decorators = [
{ type: Component, args: [{
selector: 'app-ngx-select2-ex',
template: `<span appNgxSelect2Ex
[service]="ngxSelect2ExService"
class="select2 select2-container"
[class.select2-container--below]="!disabled"
[class.select2-container--open]="isOpen"
[ngClass]="getContainerThemeClass()"
[class.select2-container--focus]="isInFocus"
[class.select2-container--disabled]="disabled"
dir="ltr">
<span class="selection">
<span class="select2-selection"
[class.select2-selection--single]="!multi"
[class.select2-selection--multiple]="multi"
role="combobox"
aria-haspopup="true"
[attr.aria-expanded]="isOpen"
[tabindex]="multi ? -1 : 0"
aria-labelledby="select2-container"
aria-owns="select2-results">
<span *ngIf="!multi" class="select2-selection__rendered" id="select2-selection-container" [title]="getTitleTooltipText()">
<span *ngIf="shouldShowPlaceholder()" class="select2-selection__placeholder">{{placeholder}}</span>
<span *ngIf="shouldShowClearSelectionButton()" class="select2-selection__clear" (click)="clearSelection()">×</span>
{{selection[0]?.value}}
</span>
<span *ngIf="!multi" class="select2-selection__arrow" role="presentation">
<b role="presentation"></b>
</span>
<ul *ngIf="multi" class="select2-selection__rendered">
<span *ngIf="shouldShowClearSelectionButton()" class="select2-selection__clear" (click)="clearSelection()">×</span>
<li *ngFor="let selectionItem of selection" class="select2-selection__choice" [title]="selectionItem.value">
<span class="select2-selection__choice__remove" role="presentation" (click)="deselect(selectionItem)">×</span>
{{selectionItem.value}}
</li>
<li class="select2-search select2-search--inline" [ngStyle]="getStyleOfSearchListItem()">
<input class="select2-search__field"
type="search"
tabindex="0"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
role="textbox"
aria-autocomplete="list"
[placeholder]="getInlineInputPlaceholder()"
[ngStyle]="getStyleOfInlineInput(search)"
[(ngModel)]="search"></li>
</ul>
</span>
</span>
<span class="dropdown-wrapper" aria-hidden="true"></span>
</span>
`,
styles: [`.select2-container{display:block}`],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxSelect2ExComponent),
multi: true
},
NgxSelect2ExService
]
},] },
];
/** @nocollapse */
NgxSelect2ExComponent.ctorParameters = () => [
{ type: NgxSelect2ExService, },
];
NgxSelect2ExComponent.propDecorators = {
"options": [{ type: Input },],
"disabled": [{ type: Input },],
"multi": [{ type: Input },],
"theme": [{ type: Input },],
"minimumResultsForSearch": [{ type: Input },],
"minimumInputLength": [{ type: Input },],
"maximumInputLength": [{ type: Input },],
"language": [{ type: Input },],
"selectOnClose": [{ type: Input },],
"closeOnSelect": [{ type: Input },],
"allowClear": [{ type: Input },],
"placeholder": [{ type: Input },],
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2OptionFilterPipe {
/**
* @param {?} options
* @param {?} filter
* @param {?} minimumResultsForSearch
* @param {?=} minimumInputLength
* @param {?=} maximumInputLength
* @return {?}
*/
transform(options, filter, minimumResultsForSearch, minimumInputLength = null, maximumInputLength = null) {
return this.filterOptions(options, filter, minimumResultsForSearch, minimumInputLength, maximumInputLength);
}
/**
* @param {?} options
* @param {?} filter
* @param {?} minimumResultsForSearch
* @param {?=} minimumInputLength
* @param {?=} maximumInputLength
* @return {?}
*/
filterOptions(options, filter, minimumResultsForSearch, minimumInputLength = null, maximumInputLength = null) {
if (options.length < minimumResultsForSearch) {
return options;
}
else if (minimumInputLength !== null && maximumInputLength !== null) {
return this.rangeInputFilteringHandler(options, filter, minimumInputLength, maximumInputLength);
}
else if (minimumInputLength !== null) {
return this.minimumInputFilteringHandler(options, filter, minimumInputLength);
}
else if (maximumInputLength !== null) {
return this.maximumInputFilteringHandler(options, filter, maximumInputLength);
}
else {
return this.doFiltering(options, filter);
}
}
/**
* @param {?} options
* @param {?} filter
* @param {?} minimumInputLength
* @param {?} maximumInputLength
* @return {?}
*/
rangeInputFilteringHandler(options, filter, minimumInputLength, maximumInputLength) {
if (this.isfilterTextBiggerThanMinimumInputLength(filter, minimumInputLength) &&
this.isfilterTextSmallerThanMaximumInputLength(filter, maximumInputLength)) {
return this.doFiltering(options, filter);
}
else {
return /** @type {?} */ ([]);
}
}
/**
* @param {?} options
* @param {?} filter
* @param {?} minimumInputLength
* @return {?}
*/
minimumInputFilteringHandler(options, filter, minimumInputLength) {
if (this.isfilterTextBiggerThanMinimumInputLength(filter, minimumInputLength)) {
return this.doFiltering(options, filter);
}
else {
return /** @type {?} */ ([]);
}
}
/**
* @param {?} options
* @param {?} filter
* @param {?} maximumInputLength
* @return {?}
*/
maximumInputFilteringHandler(options, filter, maximumInputLength) {
if (!filter || this.isfilterTextSmallerThanMaximumInputLength(filter, maximumInputLength)) {
return this.doFiltering(options, filter);
}
else {
return /** @type {?} */ ([]);
}
}
/**
* @param {?} filter
* @param {?} minimumInputLength
* @return {?}
*/
isfilterTextBiggerThanMinimumInputLength(filter, minimumInputLength) {
return filter && minimumInputLength <= filter.length;
}
/**
* @param {?} filter
* @param {?} maximumInputLength
* @return {?}
*/
isfilterTextSmallerThanMaximumInputLength(filter, maximumInputLength) {
return filter && filter.length <= maximumInputLength;
}
/**
* @param {?} options
* @param {?} filter
* @return {?}
*/
doFiltering(options, filter) {
if (filter) {
return options.filter((option) => option.value.toLowerCase().includes(filter.toLowerCase()));
}
else {
return options;
}
}
}
NgxSelect2OptionFilterPipe.decorators = [
{ type: Pipe, args: [{
name: 'ngxSelect2OptionFilter'
},] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExDropdownComponent {
/**
* @param {?} filterPipe
*/
constructor(filterPipe) {
this.filterPipe = filterPipe;
this.multi = null;
this.minimumInputLength = null;
this.maximumInputLength = null;
this.display = 'block';
this.position = 'absolute';
this.options = [];
this.subscriptions = [];
}
/**
* @return {?}
*/
ngOnInit() {
this.subscribeToOptions();
this.subscribeToDropdownPositionChanges();
this.subscribeToSearchChanges();
}
/**
* @return {?}
*/
ngOnDestroy() {
this.unsubscribe();
this.selectOnClose();
}
/**
* @param {?} hoveredOption
* @return {?}
*/
onOptionHover(hoveredOption) {
if (!hoveredOption.disabled) {
this.options.forEach((option) => {
option.highlighted = option.id === hoveredOption.id;
});
}
}
/**
* @param {?} clickedOption
* @return {?}
*/
onOptionClick(clickedOption) {
if (clickedOption.disabled) {
return;
}
if (!clickedOption.selected) {
this.service.select(clickedOption);
}
else {
this.service.deselect(clickedOption);
}
this.service.search = null;
}
/**
* @return {?}
*/
getContainerThemeClass() {
return 'select2-container--' + this.theme;
}
/**
* @return {?}
*/
shouldHideSearchBox() {
return this.options.length < this.minimumResultsForSearch || this.multi;
}
/**
* @return {?}
*/
getNoResultsMessage() {
return this.language.noResults();
}
/**
* @return {?}
*/
getInputTooShortMessage() {
return this.language.inputTooShort(this.minimumInputLength);
}
/**
* @return {?}
*/
getInputTooLongMessage() {
return this.language.inputTooLong((this.search ? this.search.length : 0) - this.maximumInputLength);
}
/**
* @return {?}
*/
shouldShowNoResultsMessage() {
return this.search &&
!this.filterPipe.filterOptions(this.options, this.search, this.minimumResultsForSearch).length &&
!this.shouldShowInputTooShortMessage() &&
!this.shouldShowInputTooLongMessage() &&
(this.multi || !this.shouldHideSearchBox());
}
/**
* @return {?}
*/
shouldShowInputTooShortMessage() {
return this.minimumInputLength !== null &&
(!this.search || this.search && this.search.length < this.minimumInputLength) &&
!this.filterPipe.filterOptions(this.options, this.search, this.minimumResultsForSearch, this.minimumInputLength).length &&
!this.shouldHideSearchBox();
}
/**
* @return {?}
*/
shouldShowInputTooLongMessage() {
return this.maximumInputLength !== null &&
this.search && this.maximumInputLength < this.search.length &&
!this.filterPipe.filterOptions(this.options, this.search, this.minimumResultsForSearch, null, this.maximumInputLength).length &&
!this.shouldHideSearchBox();
}
/**
* @return {?}
*/
subscribeToOptions() {
this.subscriptions.push(this.service.getOptionsAsObservable().subscribe((options) => this.options = options, error => console.error(error)));
}
/**
* @return {?}
*/
subscribeToDropdownPositionChanges() {
this.subscriptions.push(this.service.getDropdownPositionAsObservable().subscribe((dropdownPosition) => this.initDropdownPosition(dropdownPosition)));
}
/**
* @return {?}
*/
subscribeToSearchChanges() {
this.subscriptions.push(this.service.getSearchAsObservable().subscribe((search) => this.search = search));
}
/**
* @param {?} dropdownPosition
* @return {?}
*/
initDropdownPosition(dropdownPosition) {
this.top = dropdownPosition.top + 'px';
this.left = dropdownPosition.left + 'px';
this.width = dropdownPosition.width + 'px';
}
/**
* @return {?}
*/
selectOnClose() {
const /** @type {?} */ highlightedOption = this.options.find((option) => option.highlighted);
if (highlightedOption && this.service.selectOnClose) {
this.service.select(highlightedOption);
}
}
/**
* @return {?}
*/
unsubscribe() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
}
}
NgxSelect2ExDropdownComponent.decorators = [
{ type: Component, args: [{
selector: 'app-ngx-select2-ex-dropdown',
template: `<span class="select2-container" [ngClass]="getContainerThemeClass()" [class.select2-container--open]="true">
<span id="select2-dropdown" class="select2-dropdown select2-dropdown--below" dir="ltr">
<span *ngIf="!multi" class="select2-search select2-search--dropdown" [class.select2-search--hide]="shouldHideSearchBox()">
<input appNgxSelect2ExDropdownSearchField
class="select2-search__field"
type="search" tabindex="0"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
role="textbox"
[(ngModel)]="search">
</span>
<span class="select2-results">
<ul class="select2-results__options" role="tree" id="select2-results" aria-expanded="true" aria-hidden="false">
<li *ngFor="let option of options | ngxSelect2OptionFilter: search:minimumResultsForSearch:minimumInputLength:maximumInputLength"
class="select2-results__option"
[class.select2-results__option--highlighted]="option.highlighted"
role="treeitem"
[attr.aria-selected]="option.selected"
[attr.aria-disabled]="option.disabled ? option.disabled : null"
(mouseover)="onOptionHover(option)"
(mousedown)="onOptionClick(option)">
{{option.value}}
</li>
<li *ngIf="shouldShowNoResultsMessage()"
role="treeitem"
aria-live="assertive"
class="select2-results__option select2-results__message">
{{getNoResultsMessage()}}
</li>
<li *ngIf="shouldShowInputTooShortMessage()"
role="treeitem"
aria-live="assertive"
class="select2-results__option select2-results__message">
{{getInputTooShortMessage()}}
</li>
<li *ngIf="shouldShowInputTooLongMessage()"
role="treeitem"
aria-live="assertive"
class="select2-results__option select2-results__message">
{{getInputTooLongMessage()}}
</li>
</ul>
</span>
</span>
</span>
`,
styles: [`.select2-container{display:block}`]
},] },
];
/** @nocollapse */
NgxSelect2ExDropdownComponent.ctorParameters = () => [
{ type: NgxSelect2OptionFilterPipe, },
];
NgxSelect2ExDropdownComponent.propDecorators = {
"service": [{ type: Input },],
"multi": [{ type: Input },],
"theme": [{ type: Input },],
"minimumResultsForSearch": [{ type: Input },],
"minimumInputLength": [{ type: Input },],
"maximumInputLength": [{ type: Input },],
"language": [{ type: Input },],
"display": [{ type: HostBinding, args: ['style.display',] },],
"position": [{ type: HostBinding, args: ['style.position',] },],
"top": [{ type: HostBinding, args: ['style.top',] },],
"left": [{ type: HostBinding, args: ['style.left',] },],
"right": [{ type: HostBinding, args: ['style.right',] },],
"width": [{ type: HostBinding, args: ['style.width',] },],
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExDropdownInjectionService {
/**
* @param {?} applicationRef
* @param {?} componentFactoryResolver
* @param {?} injector
*/
constructor(applicationRef, componentFactoryResolver, injector) {
this.applicationRef = applicationRef;
this.componentFactoryResolver = componentFactoryResolver;
this.injector = injector;
}
/**
* @return {?}
*/
getRootViewContainer() {
if (this._container) {
return this._container;
}
const /** @type {?} */ rootComponents = this.applicationRef['components'];
if (rootComponents.length) {
return rootComponents[0];
}
throw new Error('View Container not found! ngUpgrade needs to manually set this via setRootViewContainer.');
}
/**
* @param {?} container
* @return {?}
*/
setRootViewContainer(container) {
this._container = container;
}
/**
* @param {?} componentRef
* @return {?}
*/
getComponentRootNode(componentRef) {
return /** @type {?} */ ((/** @type {?} */ (componentRef.hostView)).rootNodes[0]);
}
/**
* @return {?}
*/
getRootViewContainerNode() {
return this.getComponentRootNode(this.getRootViewContainer());
}
/**
* @param {?} component
* @param {?} options
* @return {?}
*/
projectComponentInputs(component, options) {
if (options) {
const /** @type {?} */ props = Object.getOwnPropertyNames(options);
for (const /** @type {?} */ prop of props) {
component.instance[prop] = options[prop];
}
}
return component;
}
/**
* @template T
* @param {?} componentClass
* @param {?=} options
* @param {?=} location
* @return {?}
*/
appendComponent(componentClass, options = {}, location = this.getRootViewContainerNode()) {
const /** @type {?} */ componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentClass);
const /** @type {?} */ componentRef = componentFactory.create(this.injector);
const /** @type {?} */ appRef = this.applicationRef;
const /** @type {?} */ componentRootNode = this.getComponentRootNode(componentRef);
// project the options passed to the component instance
this.projectComponentInputs(componentRef, options);
appRef.attachView(componentRef.hostView);
componentRef.onDestroy(() => {
appRef.detachView(componentRef.hostView);
});
location.appendChild(componentRootNode);
return componentRef;
}
}
NgxSelect2ExDropdownInjectionService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
NgxSelect2ExDropdownInjectionService.ctorParameters = () => [
{ type: ApplicationRef, },
{ type: ComponentFactoryResolver, },
{ type: Injector, },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* @return {?}
*/
function _window() {
// return the global native browser window object
return window;
}
class WindowRef {
constructor() { }
/**
* @return {?}
*/
get nativeWindow() {
return _window();
}
}
WindowRef.decorators = [
{ type: Injectable },
];
/** @nocollapse */
WindowRef.ctorParameters = () => [];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExDirective {
/**
* @param {?} el
* @param {?} renderer
* @param {?} ngxSelect2ExDropdownInjectionService
* @param {?} winRef
*/
constructor(el, renderer, ngxSelect2ExDropdownInjectionService, winRef) {
this.el = el;
this.renderer = renderer;
this.ngxSelect2ExDropdownInjectionService = ngxSelect2ExDropdownInjectionService;
this.winRef = winRef;
this.subscriptions = [];
}
/**
* @return {?}
*/
ngOnInit() {
this.updateDropdownPosition();
this.subscribeToSearchChanges();
}
/**
* @return {?}
*/
ngOnDestroy() {
this.unsubscribe();
}
/**
* @param {?} targetElement
* @return {?}
*/
onClick(targetElement) {
const /** @type {?} */ dropdown = this.compRef ? this.compRef.location.nativeElement : null;
const /** @type {?} */ clickedClearButton = targetElement.className === 'select2-selection__clear';
const /** @type {?} */ clickedDisabledOption = targetElement.hasAttribute('aria-disabled');
const /** @type {?} */ clickedNoOptionListItem = targetElement.className.includes('select2-results__message');
const /** @type {?} */ clickedSearchField = targetElement.className.includes('select2-search__field');
const /** @type {?} */ clickedRemoveChoice = targetElement.className.includes('select2-selection__choice__remove');
const /** @type {?} */ clickedDropdown = dropdown && dropdown.contains(targetElement);
const /** @type {?} */ clickedInside = this.el.nativeElement.contains(targetElement) || clickedDropdown;
if (clickedInside && !this.service.isOpen) {
this.service.isInFocus = false;
if (!this.service.disabled) {
this.openDropdown();
}
}
else if (clickedInside && this.service.isOpen) {
if (clickedDisabledOption || clickedNoOptionListItem || clickedSearchField || clickedClearButton) {
this.service.isInFocus = false;
}
else {
if (this.service.closeOnSelect || !clickedDropdown) {
this.service.isInFocus = true;
if (!clickedRemoveChoice) {
this.closeDropdown();
}
}
}
}
else if (!clickedInside && this.service.isOpen) {
this.service.isInFocus = false;
this.closeDropdown();
}
else if (!clickedInside && !this.service.isOpen) {
this.service.isInFocus = false;
}
if (clickedInside) {
if (!this.service.disabled) {
this.setFocusForSearchField(this.compRef ? this.compRef.location.nativeElement : null);
}
if (this.service.multi && !clickedNoOptionListItem) {
this.service.search = null;
}
}
}
/**
* @return {?}
*/
resize() {
this.updateDropdownPosition();
}
/**
* @return {?}
*/
openDropdown() {
this.compRef = this.ngxSelect2ExDropdownInjectionService.appendComponent(NgxSelect2ExDropdownComponent, {
service: this.service,
multi: this.service.multi,
theme: this.service.theme,
minimumResultsForSearch: this.service.minimumResultsForSearch,
minimumInputLength: this.service.minimumInputLength,
maximumInputLength: this.service.maximumInputLength,
language: this.service.language
});
this.service.isOpen = true;
this.updateDropdownPosition();
}
/**
* @return {?}
*/
closeDropdown() {
if (this.compRef) {
this.compRef.destroy();
this.compRef = null;
}
this.service.isOpen = false;
}
/**
* @param {?} targetElement
* @return {?}
*/
setFocusForSearchField(targetElement) {
const /** @type {?} */ inlineSearchField = this.el.nativeElement ? this.el.nativeElement.getElementsByClassName('select2-search__field') : null;
if (inlineSearchField && inlineSearchField.length) {
inlineSearchField[0].focus();
}
}
/**
* @return {?}
*/
subscribeToSearchChanges() {
this.subscriptions.push(this.service.getSearchAsObservable().subscribe((search) => {
if (this.service.multi) {
if (search && !this.service.isOpen) {
if (!this.service.disabled) {
this.openDropdown();
}
}
this.updateDropdownPosition();
}
}));
}
/**
* @return {?}
*/
updateDropdownPosition() {
this.renderer.setStyle(this.el.nativeElement, 'width', '100%');
const /** @type {?} */ boundingClientRect = this.el.nativeElement.getBoundingClientRect();
const /** @type {?} */ offsetTop = boundingClientRect.bottom + this.winRef.nativeWindow.scrollY;
const /** @type {?} */ dropdownPosition = {
top: offsetTop,
left: boundingClientRect.left,
width: boundingClientRect.width
};
this.service.dropdownPosition = dropdownPosition;
this.renderer.setStyle(this.el.nativeElement, 'width', `${boundingClientRect.width}px`);
}
/**
* @return {?}
*/
unsubscribe() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
}
}
NgxSelect2ExDirective.decorators = [
{ type: Directive, args: [{
selector: '[appNgxSelect2Ex]',
providers: [WindowRef]
},] },
];
/** @nocollapse */
NgxSelect2ExDirective.ctorParameters = () => [
{ type: ElementRef, },
{ type: Renderer2, },
{ type: NgxSelect2ExDropdownInjectionService, },
{ type: WindowRef, },
];
NgxSelect2ExDirective.propDecorators = {
"service": [{ type: Input },],
"onClick": [{ type: HostListener, args: ['document:mouseup', ['$event.target'],] },],
"resize": [{ type: HostListener, args: ['window:resize',] },],
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExDropdownSearchFieldDirective {
/**
* @param {?} el
*/
constructor(el) {
this.el = el;
}
/**
* @return {?}
*/
ngOnInit() {
this.setFocusForDropdownSearchField();
}
/**
* @return {?}
*/
setFocusForDropdownSearchField() {
this.el.nativeElement.focus();
}
}
NgxSelect2ExDropdownSearchFieldDirective.decorators = [
{ type: Directive, args: [{
selector: '[appNgxSelect2ExDropdownSearchField]'
},] },
];
/** @nocollapse */
NgxSelect2ExDropdownSearchFieldDirective.ctorParameters = () => [
{ type: ElementRef, },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class NgxSelect2ExModule {
}
NgxSelect2ExModule.decorators = [
{ type: NgModule, args: [{
imports: [
CommonModule,
FormsModule
],
declarations: [
NgxSelect2ExComponent,
NgxSelect2ExDropdownComponent,
NgxSelect2ExDirective,
NgxSelect2ExDropdownSearchFieldDirective,
NgxSelect2OptionFilterPipe
],
exports: [NgxSelect2ExComponent],
entryComponents: [NgxSelect2ExDropdownComponent],
providers: [
NgxSelect2ExDropdownInjectionService,
NgxSelect2OptionFilterPipe
]
},] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* Generated bundle index. Do not edit.
*/
export { NgxSelect2ExModule, NgxSelect2ExDropdownComponent as ɵc, NgxSelect2ExComponent as ɵa, NgxSelect2ExDropdownSearchFieldDirective as ɵh, NgxSelect2ExDirective as ɵe, NgxSelect2OptionFilterPipe as ɵd, NgxSelect2ExDropdownInjectionService as ɵg, NgxSelect2ExService as ɵb, WindowRef as ɵf };
//# sourceMappingURL=ngx-select2-ex.js.map