vc-select-dropdown
Version:
A angular(4+) select dropdown for single select or multiselct module.
504 lines • 23.3 kB
JavaScript
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
import { ArrayFilterPipe } from "./../../pipes/filter-by.pipe";
import { Component, Input, EventEmitter, Output, HostListener, ViewChildren, ElementRef, ChangeDetectorRef, forwardRef } from "@angular/core";
import { NG_VALUE_ACCESSOR } from "@angular/forms";
var SelectDropDownComponent = /** @class */ (function () {
function SelectDropDownComponent(cdref, _elementRef) {
this.cdref = cdref;
this._elementRef = _elementRef;
/**
* Get the required inputs
*/
this.options = [];
/**
* configuration options
*/
this.config = {};
/**
* Whether multiple selection or single selection allowed
*/
this.multiple = false;
/**
* change event when value changes to provide user to handle things in change event
*/
this.change = new EventEmitter();
/**
* The search text change event emitter emitted when user type in the search input
*/
this.searchChange = new EventEmitter();
/**
* Event emitted when dropdown is open.
*/
this.open = new EventEmitter();
/**
* Event emitted when dropdown is open.
*/
this.close = new EventEmitter();
/**
* Toogle the dropdown list
*/
this.toggleDropdown = false;
/**
* Available items for selection
*/
this.availableItems = [];
/**
* Selected Items
*/
this.selectedItems = [];
/**
* Selection text to be Displayed
*/
this.selectedDisplayText = "Select";
/**
* variable to track if clicked inside or outside of component
*/
this.clickedInside = false;
/**
* variable to track keypress event inside and outsid of component
*/
this.insideKeyPress = false;
/**
* variable to track the focused item whenuser uses arrow keys to select item
*/
this.focusedItemIndex = null;
/**
* element to show not found text when not itmes match the search
*/
this.showNotFound = false;
this.onChange = function () {
// empty
};
this.onTouched = function () {
// empty
};
this.multiple = false;
}
Object.defineProperty(SelectDropDownComponent.prototype, "value", {
get: function () {
return this._value;
},
set: function (val) {
this._value = val;
this.onChange(val);
this.onTouched();
},
enumerable: true,
configurable: true
});
/**
* click listener for host inside this component i.e
* if many instances are there, this detects if clicked inside
* this instance
*/
SelectDropDownComponent.prototype.clickInsideComponent = function () {
this.clickedInside = true;
};
/**
* click handler on documnent to hide the open dropdown if clicked outside
*/
SelectDropDownComponent.prototype.clickOutsideComponent = function () {
if (!this.clickedInside) {
this.toggleDropdown = false;
this.resetArrowKeyActiveElement();
// clear searh on close
this.searchText = null;
this.close.emit();
}
this.clickedInside = false;
};
/**
* click handler on documnent to hide the open dropdown if clicked outside
*/
SelectDropDownComponent.prototype.KeyPressOutsideComponent = function () {
if (!this.insideKeyPress) {
this.toggleDropdown = false;
this.resetArrowKeyActiveElement();
}
this.insideKeyPress = false;
};
/**
* Event handler for key up and down event and enter press for selecting element
* @param event
*/
SelectDropDownComponent.prototype.handleKeyboardEvent = function ($event) {
this.insideKeyPress = true;
if ($event.keyCode === 27 || this.disabled) {
this.toggleDropdown = false;
this.insideKeyPress = false;
return;
}
var avaOpts = this.availableOptions.toArray();
if (avaOpts.length === 0 && !this.toggleDropdown) {
this.toggleDropdown = true;
}
// Arrow Down
if ($event.keyCode === 40 && avaOpts.length > 0) {
this.onArrowKeyDown();
/* istanbul ignore else */
if (this.focusedItemIndex >= avaOpts.length) {
this.focusedItemIndex = 0;
}
avaOpts[this.focusedItemIndex].nativeElement.focus();
$event.preventDefault();
}
// Arrow Up
if ($event.keyCode === 38 && avaOpts.length) {
this.onArrowKeyUp();
/* istanbul ignore else */
if (this.focusedItemIndex >= avaOpts.length) {
this.focusedItemIndex = avaOpts.length - 1;
}
avaOpts[this.focusedItemIndex].nativeElement.focus();
$event.preventDefault();
}
// Enter
if ($event.keyCode === 13 && this.focusedItemIndex !== null) {
var filteredItems = new ArrayFilterPipe().transform(this.availableItems, this.searchText, this.config.searchOnKey);
this.selectItem(filteredItems[this.focusedItemIndex], this.availableItems.indexOf(filteredItems[this.focusedItemIndex]));
return false;
}
};
/**
* Component onInit
*/
SelectDropDownComponent.prototype.ngOnInit = function () {
if (typeof this.options !== "undefined" && Array.isArray(this.options)) {
this.availableItems = this.options.sort(this.config.customComparator).slice();
this.initDropdownValuesAndOptions();
}
};
/**
* after view init to subscribe to available option changes
*/
SelectDropDownComponent.prototype.ngAfterViewInit = function () {
this.availableOptions.changes.subscribe(this.setNotFoundState.bind(this));
};
SelectDropDownComponent.prototype.registerOnChange = function (fn) {
this.onChange = fn;
};
SelectDropDownComponent.prototype.registerOnTouched = function (fn) {
this.onTouched = fn;
};
SelectDropDownComponent.prototype.setDisabledState = function (isDisabled) {
this.disabled = isDisabled;
};
SelectDropDownComponent.prototype.writeValue = function (value, internal) {
if (value) {
if (Array.isArray(value)) {
if (this.multiple) {
this.value = value;
}
else {
this.value = value[0];
}
}
else {
this.value = value;
}
/* istanbul ignore else */
if (this.selectedItems.length === 0) {
if (Array.isArray(value)) {
this.selectedItems = value;
}
else {
this.selectedItems.push(value);
}
this.initDropdownValuesAndOptions();
}
}
else {
// this.value = [];
/* istanbul ignore else */
if (!internal) {
this.reset();
}
}
/* istanbul ignore else */
if (!internal) {
this.reset();
}
};
SelectDropDownComponent.prototype.reset = function () {
this.selectedItems = [];
this.availableItems = this.options.sort(this.config.customComparator).slice();
this.initDropdownValuesAndOptions();
};
/**
* function sets whether to show items not found text or not
*/
SelectDropDownComponent.prototype.setNotFoundState = function () {
if (this.availableOptions.length === 0) {
this.showNotFound = true;
}
else {
this.showNotFound = false;
}
this.cdref.detectChanges();
};
/**
* Component onchage i.e when any of the input properties change
* @param changes
*/
SelectDropDownComponent.prototype.ngOnChanges = function (changes) {
this.selectedItems = [];
this.searchText = null;
this.options = this.options || [];
/* istanbul ignore else */
if (changes.options) {
this.availableItems = this.options.sort(this.config.customComparator).slice();
}
/* istanbul ignore else */
if (changes.value) {
/* istanbul ignore else */
if (JSON.stringify(changes.value.currentValue) === JSON.stringify([])) {
this.availableItems = this.options.sort(this.config.customComparator).slice();
}
}
this.initDropdownValuesAndOptions();
};
/**
* Deselct a selected items
* @param item: item to be deselected
* @param index: index of the item
*/
SelectDropDownComponent.prototype.deselectItem = function (item, index) {
var _this = this;
if (this.selectedItems.length <= 1 && this.config.mustHaveAValue) {
return;
}
this.selectedItems.forEach(function (element, i) {
/* istanbul ignore else */
if (item === element) {
_this.selectedItems.splice(i, 1);
}
});
/* istanbul ignore else */
if (!this.availableItems.includes(item)) {
this.availableItems.push(item);
this.availableItems.sort(this.config.customComparator);
}
this.selectedItems = this.selectedItems.slice();
this.availableItems = this.availableItems.slice();
this.valueChanged();
this.resetArrowKeyActiveElement();
};
/**
* Select an item
* @param item: item to be selected
* @param index: index of the item
*/
SelectDropDownComponent.prototype.selectItem = function (item, index) {
var _this = this;
/* istanbul ignore else */
if (!this.multiple) {
/* istanbul ignore else */
if (this.selectedItems.length > 0) {
this.availableItems.push(this.selectedItems[0]);
}
this.selectedItems = [];
this.toggleDropdown = false;
}
this.availableItems.forEach(function (element, i) {
/* istanbul ignore else */
if (item === element) {
_this.selectedItems.push(item);
_this.availableItems.splice(i, 1);
}
});
/* istanbul ignore else */
if (this.config.clearOnSelection) {
this.searchText = null;
}
this.selectedItems = this.selectedItems.slice();
this.availableItems = this.availableItems.slice();
this.selectedItems.sort(this.config.customComparator);
this.availableItems.sort(this.config.customComparator);
// this.searchText = null;
this.valueChanged();
this.resetArrowKeyActiveElement();
};
/**
* When selected items changes trigger the chaange back to parent
*/
SelectDropDownComponent.prototype.valueChanged = function () {
this.writeValue(this.selectedItems, true);
// this.valueChange.emit(this.value);
this.change.emit({ value: this.value });
this.setSelectedDisplayText();
};
/**
* Toggle the dropdownlist on/off
*/
SelectDropDownComponent.prototype.toggleSelectDropdown = function () {
this.toggleDropdown = !this.toggleDropdown;
if (this.toggleDropdown) {
this.open.emit();
}
else {
this.searchText = null;
this.close.emit();
}
this.resetArrowKeyActiveElement();
};
/**
* The change handler for search text
*/
SelectDropDownComponent.prototype.searchTextChanged = function () {
this.searchChange.emit(this.searchText);
};
/**
* initialize the config and other properties
*/
SelectDropDownComponent.prototype.initDropdownValuesAndOptions = function () {
var _this = this;
var config = {
displayKey: "description",
height: "auto",
search: false,
placeholder: "Select",
searchPlaceholder: "Search...",
limitTo: this.options.length,
customComparator: undefined,
noResultsFound: "No results found!",
moreText: "more",
searchOnKey: null,
clearOnSelection: false,
mustHaveAValue: false
};
/* istanbul ignore else */
if (this.config === "undefined" || Object.keys(this.config).length === 0) {
this.config = __assign({}, config);
}
for (var _i = 0, _a = Object.keys(config); _i < _a.length; _i++) {
var key = _a[_i];
this.config[key] = this.config[key] ? this.config[key] : config[key];
}
// Adding placeholder in config as default param
this.selectedDisplayText = this.config["placeholder"];
/* istanbul ignore else */
if (this.value !== "" && typeof this.value !== "undefined") {
if (Array.isArray(this.value)) {
this.selectedItems = this.value;
}
else {
this.selectedItems[0] = this.value;
}
this.selectedItems.forEach(function (item) {
var ind = _this.availableItems.findIndex(function (aItem) { return JSON.stringify(item) === JSON.stringify(aItem); });
if (ind !== -1) {
_this.availableItems.splice(ind, 1);
}
});
}
this.setSelectedDisplayText();
};
/**
* set the text to be displayed
*/
SelectDropDownComponent.prototype.setSelectedDisplayText = function () {
var text = this.selectedItems[0];
/* istanbul ignore else */
if (typeof this.selectedItems[0] === "object") {
text = this.selectedItems[0][this.config.displayKey];
}
if (this.multiple && this.selectedItems.length > 0) {
this.selectedDisplayText =
this.selectedItems.length === 1
? text
: text +
(" + " + (this.selectedItems.length - 1) + " " + this.config.moreText);
}
else {
this.selectedDisplayText =
this.selectedItems.length === 0 ? this.config.placeholder : text;
}
};
/**
* Event handler for arrow key up event thats focuses on a item
*/
SelectDropDownComponent.prototype.onArrowKeyUp = function () {
/* istanbul ignore else */
if (this.focusedItemIndex === 0) {
this.focusedItemIndex = this.availableItems.length - 1;
return;
}
/* istanbul ignore else */
if (this.onArrowKey()) {
this.focusedItemIndex--;
}
};
/**
* Event handler for arrow key down event thats focuses on a item
*/
SelectDropDownComponent.prototype.onArrowKeyDown = function () {
/* istanbul ignore else */
if (this.focusedItemIndex === this.availableItems.length - 1) {
this.focusedItemIndex = 0;
return;
}
/* istanbul ignore else */
if (this.onArrowKey()) {
this.focusedItemIndex++;
}
};
SelectDropDownComponent.prototype.onArrowKey = function () {
/* istanbul ignore else */
if (this.focusedItemIndex === null) {
this.focusedItemIndex = 0;
return false;
}
return true;
};
/**
* will reset the element that is marked active using arrow keys
*/
SelectDropDownComponent.prototype.resetArrowKeyActiveElement = function () {
this.focusedItemIndex = null;
};
SelectDropDownComponent.decorators = [
{ type: Component, args: [{
selector: "ngx-select-dropdown",
template: "\n <div class=\"ngx-dropdown-container\" tabindex=\"0\">\n <button type=\"button\" class=\"ngx-dropdown-button\" [ngClass]=\"{'disabled':disabled}\" [disabled]=\"disabled\"\n (click)=\"toggleSelectDropdown()\">\n <span>{{selectedDisplayText}} </span>\n <span class=\"nsdicon-angle-down\"></span>\n </button>\n <div class=\"ngx-dropdown-list-container\" *ngIf=\"toggleDropdown\" [style.maxHeight]=\"config.height\">\n <div class=\"search-container\" *ngIf=\"config.search\">\n <input name=\"search-text\" (input)=\"searchTextChanged()\" [(ngModel)]=\"searchText\" autocomplete=\"off\" />\n <label [ngClass]=\"{'active': searchText}\">\n <span class=\"nsdicon-search\"></span> {{config.searchPlaceholder}}</label>\n </div>\n <ul class=\"selected-items\">\n <li tabindex=\"-1\" *ngFor=\"let selected of selectedItems;let i = index\" (click)=\"deselectItem(selected,i)\">\n <span *ngIf=\"selectedItems.length > 1 || !config.mustHaveAValue\" class=\"nsdicon-close\">x</span>\n <span> {{selected[config.displayKey] || selected}}</span>\n </li>\n </ul>\n <hr *ngIf=\"selectedItems.length > 0 && availableItems.length > 0\" />\n <ul class=\"available-items\">\n <li #availableOption\n *ngFor=\"let item of availableItems| filterBy: searchText : config.searchOnKey | limitTo : config.limitTo;let i = index\"\n tabindex=\"-1\" [ngClass]=\"{'active': focusedItemIndex == i}\" (click)=\"selectItem(item,i)\">\n {{item[config.displayKey] || item}}</li>\n <li *ngIf=\"showNotFound\">{{config.noResultsFound}}</li>\n </ul>\n </div>\n </div>\n ",
styles: ["\n .ngx-dropdown-container{width:100%;position:relative}.ngx-dropdown-container button{display:inline-block;margin-bottom:0;font-weight:400;line-height:1.42857143;vertical-align:middle;touch-action:manipulation;cursor:pointer;user-select:none;border:1px solid #ccc;border-radius:4px;color:#333;background-color:#fff;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis;text-align:left}.ngx-dropdown-container button span{display:inline;vertical-align:middle}.ngx-dropdown-container button .nsdicon-angle-down{right:5px;position:relative;float:right}.ngx-dropdown-container button .nsdicon-angle-down::before{border-style:solid;border-width:0.1em 0.1em 0 0;content:'';display:inline-block;height:10px;position:relative;vertical-align:text-top;width:10px;top:0;transform:rotate(135deg)}.ngx-dropdown-container .ngx-dropdown-button{width:100%;min-height:30px;padding:5px 10px 5px 10px;background-color:white}.ngx-dropdown-container .ngx-dropdown-list-container{box-sizing:border-box;border:1px solid rgba(0,0,0,0.15);border-radius:4px;padding-left:10px;padding-right:10px;z-index:999999999;width:100%;background-clip:padding-box;background:white;position:absolute;-webkit-box-shadow:5px 5px 5px 0px rgba(0,0,0,0.21);-moz-box-shadow:5px 5px 5px 0px rgba(0,0,0,0.21);box-shadow:5px 5px 5px 0px rgba(0,0,0,0.21);overflow-y:auto}.ngx-dropdown-container .ngx-dropdown-list-container .search-container{position:relative;padding-top:10px;margin-top:5px}.ngx-dropdown-container .ngx-dropdown-list-container .search-container input{background-color:transparent;border:none;border-bottom:1px solid #9e9e9e;border-radius:0;outline:none;height:2rem;width:100%;font-size:13px;margin:0;padding:0;box-shadow:none;box-sizing:content-box;transition:all 0.3s}.ngx-dropdown-container .ngx-dropdown-list-container .search-container input:focus{border-bottom:1px solid #26a69a}.ngx-dropdown-container .ngx-dropdown-list-container .search-container input:focus+label{transform:translateY(-2px) scale(0.8);transform-origin:0 0}.ngx-dropdown-container .ngx-dropdown-list-container .search-container label{color:#9e9e9e;position:absolute;top:0;left:0;height:100%;font-size:1rem;cursor:text;-webkit-transition:-webkit-transform 0.2s ease-out;transition:-webkit-transform 0.2s ease-out;transition:transform 0.2s ease-out;transition:transform 0.2s ease-out, -webkit-transform 0.2s ease-out;-webkit-transform-origin:0% 100%;transform-origin:0% 100%;text-align:initial;transform:translateY(12px);pointer-events:none}.ngx-dropdown-container .ngx-dropdown-list-container .search-container label.active{transform:translateY(-2px) scale(0.8);transform-origin:0 0}.ngx-dropdown-container .ngx-dropdown-list-container ul{margin-top:1rem;margin-bottom:1rem;list-style-type:none;padding-left:0px}.ngx-dropdown-container .ngx-dropdown-list-container ul.selected-items li{background-color:#337ab7;color:white;margin-bottom:2px}.ngx-dropdown-container .ngx-dropdown-list-container ul.selected-items li .nsdicon-close{font-weight:bold;font-size:large}.ngx-dropdown-container .ngx-dropdown-list-container ul.available-items li.active{background-color:#337ab7;color:#ffff}.ngx-dropdown-container .ngx-dropdown-list-container ul li{font-size:inherit;cursor:pointer;display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:normal}.ngx-dropdown-container .disabled{pointer-events:none;background-color:#e9ecef;opacity:1;cursor:no-drop}\n "],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(function () { return SelectDropDownComponent; }),
multi: true
}
]
},] },
];
/** @nocollapse */
SelectDropDownComponent.ctorParameters = function () { return [
{ type: ChangeDetectorRef, },
{ type: ElementRef, },
]; };
SelectDropDownComponent.propDecorators = {
'_value': [{ type: Input },],
'options': [{ type: Input },],
'config': [{ type: Input },],
'multiple': [{ type: Input },],
'disabled': [{ type: Input },],
'change': [{ type: Output },],
'searchChange': [{ type: Output },],
'open': [{ type: Output },],
'close': [{ type: Output },],
'availableOptions': [{ type: ViewChildren, args: ["availableOption",] },],
'clickInsideComponent': [{ type: HostListener, args: ["click",] },],
'clickOutsideComponent': [{ type: HostListener, args: ["document:click",] },],
'KeyPressOutsideComponent': [{ type: HostListener, args: ["document:keydown",] },],
'handleKeyboardEvent': [{ type: HostListener, args: ["keydown", ["$event"],] },],
};
return SelectDropDownComponent;
}());
export { SelectDropDownComponent };
//# sourceMappingURL=ngx-select-dropdown.component.js.map