ngx-bootrap-multiselect
Version:
Customizable multiselect dropdown in Angular 2 with bootstrap css.
760 lines (751 loc) • 34.7 kB
JavaScript
import { Pipe, forwardRef, EventEmitter, Component, ChangeDetectionStrategy, IterableDiffers, ChangeDetectorRef, Input, Output, Directive, ElementRef, Host, HostListener, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { CommonModule } from '@angular/common';
class MultiSelectSearchFilter {
constructor() {
this._searchCache = {};
this._searchCacheInclusive = {};
this._prevSkippedItems = {};
}
transform(options, str = '', limit = 0, renderLimit = 0, searchFunction) {
str = str.toLowerCase();
// Drop cache because options were updated
if (options !== this._lastOptions) {
this._lastOptions = options;
this._searchCache = {};
this._searchCacheInclusive = {};
this._prevSkippedItems = {};
}
const filteredOpts = this._searchCache.hasOwnProperty(str)
? this._searchCache[str]
: this._doSearch(options, str, limit, searchFunction);
const isUnderLimit = options.length <= limit;
return isUnderLimit
? filteredOpts
: this._limitRenderedItems(filteredOpts, renderLimit);
}
_getSubsetOptions(options, prevOptions, prevSearchStr) {
const prevInclusiveOrIdx = this._searchCacheInclusive[prevSearchStr];
if (prevInclusiveOrIdx === true) {
// If have previous results and it was inclusive, do only subsearch
return prevOptions;
}
else if (typeof prevInclusiveOrIdx === 'number') {
// Or reuse prev results with unchecked ones
return [...prevOptions, ...options.slice(prevInclusiveOrIdx)];
}
return options;
}
_doSearch(options, str, limit, searchFunction) {
const prevStr = str.slice(0, -1);
const prevResults = this._searchCache[prevStr];
const prevResultShift = this._prevSkippedItems[prevStr] || 0;
if (prevResults) {
options = this._getSubsetOptions(options, prevResults, prevStr);
}
const optsLength = options.length;
const maxFound = limit > 0 ? Math.min(limit, optsLength) : optsLength;
const regexp = searchFunction(str);
const filteredOpts = [];
let i = 0, founded = 0, removedFromPrevResult = 0;
const doesOptionMatch = (option) => regexp.test(option.name);
const getChildren = (option) => options.filter(child => child.parentId === option.id);
const getParent = (option) => options.find(parent => option.parentId === parent.id);
const foundFn = (item) => { filteredOpts.push(item); founded++; };
const notFoundFn = prevResults ? () => removedFromPrevResult++ : () => { };
for (; i < optsLength && founded < maxFound; ++i) {
const option = options[i];
const directMatch = doesOptionMatch(option);
if (directMatch) {
foundFn(option);
continue;
}
if (typeof option.parentId === 'undefined') {
const childrenMatch = getChildren(option).some(doesOptionMatch);
if (childrenMatch) {
foundFn(option);
continue;
}
}
if (typeof option.parentId !== 'undefined') {
const parentMatch = doesOptionMatch(getParent(option));
if (parentMatch) {
foundFn(option);
continue;
}
}
notFoundFn();
}
const totalIterations = i + prevResultShift;
this._searchCache[str] = filteredOpts;
this._searchCacheInclusive[str] = i === optsLength || totalIterations;
this._prevSkippedItems[str] = removedFromPrevResult + prevResultShift;
return filteredOpts;
}
_limitRenderedItems(items, limit) {
return items.length > limit && limit > 0 ? items.slice(0, limit) : items;
}
}
MultiSelectSearchFilter.decorators = [
{ type: Pipe, args: [{
name: 'searchFilter'
},] }
];
const MULTISELECT_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxDropdownMultiselectComponent),
multi: true,
};
// tslint:disable-next-line: no-conflicting-lifecycle
class NgxDropdownMultiselectComponent {
constructor(fb, searchFilter, differs, cdRef) {
this.fb = fb;
this.searchFilter = searchFilter;
this.cdRef = cdRef;
this.localIsVisible = false;
this.workerDocClicked = false;
this.filterControl = this.fb.control('');
this.disabled = false;
this.disabledSelection = false;
this.searchFunction = this._escapeRegExp;
this.selectionLimitReached = new EventEmitter();
this.dropdownClosed = new EventEmitter();
this.dropdownOpened = new EventEmitter();
this.added = new EventEmitter();
this.removed = new EventEmitter();
this.lazyLoad = new EventEmitter();
this.filter = this.filterControl.valueChanges;
this.destroyed$ = new Subject();
this.filteredOptions = [];
this.lazyLoadOptions = [];
this.renderFilteredOptions = [];
this.model = [];
this.prevModel = [];
this.numSelected = 0;
this.renderItems = true;
this.checkAllSearchRegister = new Set();
this.checkAllStatus = false;
this.loadedValueIds = [];
this._focusBack = false;
this.defaultSettings = {
closeOnClickOutside: true,
pullRight: false,
enableSearch: false,
searchRenderLimit: 0,
searchRenderAfter: 1,
searchMaxLimit: 0,
searchMaxRenderedItems: 0,
checkedStyle: 'checkboxes',
buttonClasses: 'btn btn-primary dropdown-toggle',
containerClasses: 'dropdown-inline',
selectionLimit: 0,
minSelectionLimit: 0,
closeOnSelect: false,
autoUnselect: false,
showCheckAll: false,
showUncheckAll: false,
fixedTitle: false,
dynamicTitleMaxItems: 3,
maxHeight: '300px',
isLazyLoad: false,
stopScrollPropagation: false,
loadViewDistance: 1,
selectAddedValues: false,
ignoreLabels: false,
maintainSelectionOrderInTitle: false,
focusBack: true
};
this.defaultTexts = {
checkAll: 'Select all',
uncheckAll: 'Unselect all',
checked: 'selected',
checkedPlural: 'selected',
searchPlaceholder: 'Search...',
searchEmptyResult: 'Nothing found...',
searchNoRenderText: 'Type in search box to see results...',
defaultTitle: 'Select',
allSelected: 'All selected',
};
this.onModelChange = (_) => { };
this.onModelTouched = () => { };
this.differ = differs.find([]).create(null);
this.settings = this.defaultSettings;
this.texts = this.defaultTexts;
}
get focusBack() {
return this.settings.focusBack && this._focusBack;
}
set isVisible(val) {
this.localIsVisible = val;
this.workerDocClicked = val ? false : this.workerDocClicked;
}
get isVisible() {
return this.localIsVisible;
}
get searchLimit() {
return this.settings.searchRenderLimit;
}
get searchRenderAfter() {
return this.settings.searchRenderAfter;
}
get searchLimitApplied() {
return this.searchLimit > 0 && this.options.length > this.searchLimit;
}
clickedOutside() {
if (!this.isVisible || !this.settings.closeOnClickOutside) {
return;
}
this.isVisible = false;
this._focusBack = true;
this.dropdownClosed.emit();
}
getItemStyle(option) {
const style = {};
if (!option.isLabel) {
style['cursor'] = 'pointer';
}
if (option.disabled) {
style['cursor'] = 'default';
}
}
getItemStyleSelectionDisabled() {
if (this.disabledSelection) {
return { cursor: 'default' };
}
}
ngOnInit() {
this.title = this.texts.defaultTitle || '';
this.filterControl.valueChanges.pipe(takeUntil(this.destroyed$)).subscribe(() => {
this.updateRenderItems();
if (this.settings.isLazyLoad) {
this.load();
}
});
}
ngOnChanges(changes) {
if (changes['options']) {
this.options = this.options || [];
this.parents = this.options
.filter(option => typeof option.parentId === 'number')
.map(option => option.parentId);
this.updateRenderItems();
if (this.settings.isLazyLoad &&
this.settings.selectAddedValues &&
this.loadedValueIds.length === 0) {
this.loadedValueIds = this.loadedValueIds.concat(changes.options.currentValue.map(value => value.id));
}
if (this.settings.isLazyLoad &&
this.settings.selectAddedValues &&
changes.options.previousValue) {
const addedValues = changes.options.currentValue.filter(value => this.loadedValueIds.indexOf(value.id) === -1);
this.loadedValueIds.concat(addedValues.map(value => value.id));
if (this.checkAllStatus) {
this.addChecks(addedValues);
}
else if (this.checkAllSearchRegister.size > 0) {
this.checkAllSearchRegister.forEach((searchValue) => this.addChecks(this.applyFilters(addedValues, searchValue)));
}
}
if (this.texts) {
this.updateTitle();
}
this.fireModelChange();
}
if (changes['settings']) {
this.settings = Object.assign(Object.assign({}, this.defaultSettings), this.settings);
}
if (changes['texts']) {
this.texts = Object.assign(Object.assign({}, this.defaultTexts), this.texts);
if (!changes['texts'].isFirstChange()) {
this.updateTitle();
}
}
}
ngOnDestroy() {
this.destroyed$.next();
}
updateRenderItems() {
this.renderItems =
!this.searchLimitApplied ||
this.filterControl.value.length >= this.searchRenderAfter;
this.filteredOptions = this.applyFilters(this.options, this.settings.isLazyLoad ? '' : this.filterControl.value);
this.renderFilteredOptions = this.renderItems ? this.filteredOptions : [];
this.focusedItem = undefined;
}
applyFilters(options, value) {
return this.searchFilter.transform(options, value, this.settings.searchMaxLimit, this.settings.searchMaxRenderedItems, this.searchFunction);
}
fireModelChange() {
if (this.model != this.prevModel) {
this.prevModel = this.model;
this.onModelChange(this.model);
this.onModelTouched();
this.cdRef.markForCheck();
}
}
writeValue(value) {
if (value !== undefined && value !== null) {
this.model = Array.isArray(value) ? value : [value];
this.ngDoCheck();
}
else {
this.model = [];
}
}
registerOnChange(fn) {
this.onModelChange = fn;
}
registerOnTouched(fn) {
this.onModelTouched = fn;
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
ngDoCheck() {
const changes = this.differ.diff(this.model);
if (changes) {
this.updateNumSelected();
this.updateTitle();
}
}
validate(_c) {
if (this.model && this.model.length) {
return {
required: {
valid: false
}
};
}
if (this.options.filter(o => this.model.indexOf(o.id) && !o.disabled).length === 0) {
return {
selection: {
valid: false
}
};
}
return null;
}
registerOnValidatorChange(_fn) {
throw new Error('Method not implemented.');
}
clearSearch(event) {
this.maybeStopPropagation(event);
this.filterControl.setValue('');
}
toggleDropdown(e) {
if (this.isVisible) {
this._focusBack = true;
}
this.isVisible = !this.isVisible;
this.isVisible ? this.dropdownOpened.emit() : this.dropdownClosed.emit();
this.focusedItem = undefined;
}
closeDropdown(e) {
this.isVisible = true;
this.toggleDropdown(e);
}
isSelected(option) {
return this.model && this.model.indexOf(option.id) > -1;
}
setSelected(_event, option) {
if (option.isLabel) {
return;
}
if (option.disabled) {
return;
}
if (this.disabledSelection) {
return;
}
setTimeout(() => {
this.maybeStopPropagation(_event);
this.maybePreventDefault(_event);
const index = this.model.indexOf(option.id);
const isAtSelectionLimit = this.settings.selectionLimit > 0 &&
this.model.length >= this.settings.selectionLimit;
const removeItem = (idx, id) => {
this.model.splice(idx, 1);
this.removed.emit(id);
if (this.settings.isLazyLoad &&
this.lazyLoadOptions.some(val => val.id === id)) {
this.lazyLoadOptions.splice(this.lazyLoadOptions.indexOf(this.lazyLoadOptions.find(val => val.id === id)), 1);
}
};
if (index > -1) {
if (this.settings.minSelectionLimit === undefined ||
this.numSelected > this.settings.minSelectionLimit) {
removeItem(index, option.id);
}
const parentIndex = option.parentId && this.model.indexOf(option.parentId);
if (parentIndex > -1) {
removeItem(parentIndex, option.parentId);
}
else if (this.parents.indexOf(option.id) > -1) {
this.options
.filter(child => this.model.indexOf(child.id) > -1 &&
child.parentId === option.id)
.forEach(child => removeItem(this.model.indexOf(child.id), child.id));
}
}
else if (isAtSelectionLimit && !this.settings.autoUnselect) {
this.selectionLimitReached.emit(this.model.length);
return;
}
else {
const addItem = (id) => {
this.model.push(id);
this.added.emit(id);
if (this.settings.isLazyLoad &&
!this.lazyLoadOptions.some(val => val.id === id)) {
this.lazyLoadOptions.push(option);
}
};
addItem(option.id);
if (!isAtSelectionLimit) {
if (option.parentId && !this.settings.ignoreLabels) {
const children = this.options.filter(child => child.id !== option.id && child.parentId === option.parentId);
if (children.every(child => this.model.indexOf(child.id) > -1)) {
addItem(option.parentId);
}
}
else if (this.parents.indexOf(option.id) > -1) {
const children = this.options.filter(child => this.model.indexOf(child.id) < 0 && child.parentId === option.id);
children.forEach(child => addItem(child.id));
}
}
else {
removeItem(0, this.model[0]);
}
}
if (this.settings.closeOnSelect) {
this.toggleDropdown();
}
this.model = this.model.slice();
this.fireModelChange();
}, 0);
}
updateNumSelected() {
this.numSelected =
this.model.filter(id => this.parents.indexOf(id) < 0).length || 0;
}
updateTitle() {
let numSelectedOptions = this.options.length;
if (this.settings.ignoreLabels) {
numSelectedOptions = this.options.filter((option) => !option.isLabel).length;
}
if (this.numSelected === 0 || this.settings.fixedTitle) {
this.title = this.texts ? this.texts.defaultTitle : '';
}
else if (this.settings.displayAllSelectedText &&
this.model.length === numSelectedOptions) {
this.title = this.texts ? this.texts.allSelected : '';
}
else if (this.settings.dynamicTitleMaxItems &&
this.settings.dynamicTitleMaxItems >= this.numSelected) {
const useOptions = this.settings.isLazyLoad && this.lazyLoadOptions.length
? this.lazyLoadOptions
: this.options;
let titleSelections;
if (this.settings.maintainSelectionOrderInTitle) {
const optionIds = useOptions.map((selectOption, idx) => selectOption.id);
titleSelections = this.model
.map((selectedId) => optionIds.indexOf(selectedId))
.filter((optionIndex) => optionIndex > -1)
.map((optionIndex) => useOptions[optionIndex]);
}
else {
titleSelections = useOptions.filter((option) => this.model.indexOf(option.id) > -1);
}
this.title = titleSelections.map((option) => option.name).join(', ');
}
else {
this.title =
this.numSelected +
' ' +
(this.numSelected === 1
? this.texts.checked
: this.texts.checkedPlural);
}
this.cdRef.markForCheck();
}
searchFilterApplied() {
return (this.settings.enableSearch &&
this.filterControl.value &&
this.filterControl.value.length > 0);
}
addChecks(options) {
const checkedOptions = options
.filter((option) => {
if (!option.disabled &&
(this.model.indexOf(option.id) === -1 &&
!(this.settings.ignoreLabels && option.isLabel))) {
this.added.emit(option.id);
return true;
}
return false;
})
.map((option) => option.id);
this.model = this.model.concat(checkedOptions);
}
checkAll() {
if (!this.disabledSelection) {
this.addChecks(!this.searchFilterApplied() ? this.options : this.filteredOptions);
if (this.settings.isLazyLoad && this.settings.selectAddedValues) {
if (this.searchFilterApplied() && !this.checkAllStatus) {
this.checkAllSearchRegister.add(this.filterControl.value);
}
else {
this.checkAllSearchRegister.clear();
this.checkAllStatus = true;
}
this.load();
}
this.fireModelChange();
}
}
uncheckAll() {
if (!this.disabledSelection) {
const checkedOptions = this.model;
let unCheckedOptions = !this.searchFilterApplied()
? this.model
: this.filteredOptions.map((option) => option.id);
// set unchecked options only to the ones that were checked
unCheckedOptions = checkedOptions.filter(item => unCheckedOptions.indexOf(item) > -1);
this.model = this.model.filter((id) => {
if ((unCheckedOptions.indexOf(id) < 0 &&
this.settings.minSelectionLimit === undefined) ||
unCheckedOptions.indexOf(id) < this.settings.minSelectionLimit) {
return true;
}
else {
this.removed.emit(id);
return false;
}
});
if (this.settings.isLazyLoad && this.settings.selectAddedValues) {
if (this.searchFilterApplied()) {
if (this.checkAllSearchRegister.has(this.filterControl.value)) {
this.checkAllSearchRegister.delete(this.filterControl.value);
this.checkAllSearchRegister.forEach(function (searchTerm) {
const filterOptions = this.applyFilters(this.options.filter(option => unCheckedOptions.indexOf(option.id) > -1), searchTerm);
this.addChecks(filterOptions);
});
}
}
else {
this.checkAllSearchRegister.clear();
this.checkAllStatus = false;
}
this.load();
}
this.fireModelChange();
}
}
preventCheckboxCheck(event, option) {
if (option.disabled ||
(this.settings.selectionLimit &&
!this.settings.autoUnselect &&
this.model.length >= this.settings.selectionLimit &&
this.model.indexOf(option.id) === -1 &&
this.maybePreventDefault(event))) {
this.maybePreventDefault(event);
}
}
isCheckboxDisabled(option) {
return this.disabledSelection || option && option.disabled;
}
checkScrollPosition(ev) {
const scrollTop = ev.target.scrollTop;
const scrollHeight = ev.target.scrollHeight;
const scrollElementHeight = ev.target.clientHeight;
const roundingPixel = 1;
const gutterPixel = 1;
if (scrollTop >=
scrollHeight -
(1 + this.settings.loadViewDistance) * scrollElementHeight -
roundingPixel -
gutterPixel) {
this.load();
}
}
checkScrollPropagation(ev, element) {
const scrollTop = element.scrollTop;
const scrollHeight = element.scrollHeight;
const scrollElementHeight = element.clientHeight;
if ((ev.deltaY > 0 && scrollTop + scrollElementHeight >= scrollHeight) ||
(ev.deltaY < 0 && scrollTop <= 0)) {
ev = ev || window.event;
this.maybePreventDefault(ev);
ev.returnValue = false;
}
}
trackById(idx, selectOption) {
return selectOption.id;
}
load() {
this.lazyLoad.emit({
length: this.options.length,
filter: this.filterControl.value,
checkAllSearches: this.checkAllSearchRegister,
checkAllStatus: this.checkAllStatus,
});
}
focusItem(dir, e) {
if (!this.isVisible) {
return;
}
this.maybePreventDefault(e);
const idx = this.filteredOptions.indexOf(this.focusedItem);
if (idx === -1) {
this.focusedItem = this.filteredOptions[0];
return;
}
const nextIdx = idx + dir;
const newIdx = nextIdx < 0
? this.filteredOptions.length - 1
: nextIdx % this.filteredOptions.length;
this.focusedItem = this.filteredOptions[newIdx];
}
maybePreventDefault(e) {
if (e && e.preventDefault) {
e.preventDefault();
}
}
maybeStopPropagation(e) {
if (e && e.stopPropagation) {
e.stopPropagation();
}
}
_escapeRegExp(str) {
const regExpStr = str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
return new RegExp(regExpStr, 'i');
}
}
NgxDropdownMultiselectComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-bootrap-multiselect',
template: "<div *ngIf=\"options\" class=\"dropdown\" [ngClass]=\"settings.containerClasses\" [class.open]=\"isVisible\" (offClick)=\"clickedOutside()\">\n <button type=\"button\" class=\"dropdown-toggle\" [ngClass]=\"settings.buttonClasses\" (click)=\"toggleDropdown($event)\" [disabled]=\"disabled\"\n [ssAutofocus]=\"!focusBack\">\n {{ title }}\n <span class=\"caret\"></span>\n </button>\n <div #scroller *ngIf=\"isVisible\" class=\"dropdown-menu\" [ngClass]=\"{'chunkydropdown-menu': settings.checkedStyle == 'visual' }\"\n (scroll)=\"settings.isLazyLoad ? checkScrollPosition($event) : null\" (wheel)=\"settings.stopScrollPropagation ? checkScrollPropagation($event, scroller) : null\"\n [class.pull-right]=\"settings.pullRight\" [class.dropdown-menu-right]=\"settings.pullRight\" [style.max-height]=\"settings.maxHeight\"\n style=\"display: block; height: auto; overflow-y: auto;\" (keydown.tab)=\"focusItem(1, $event)\" (keydown.shift.tab)=\"focusItem(-1, $event)\">\n <div class=\"input-group search-container\" *ngIf=\"settings.enableSearch && renderFilteredOptions.length > 1\">\n <div class=\"input-group-prepend\">\n <span class=\"input-group-text\" id=\"basic-addon1\">\n <i class=\"fa fa-search\" aria-hidden=\"true\"></i>\n </span>\n </div>\n <input type=\"text\" class=\"form-control\" ssAutofocus [formControl]=\"filterControl\" [placeholder]=\"texts.searchPlaceholder\"\n class=\"form-control\">\n <div class=\"input-group-append\" *ngIf=\"filterControl.value.length>0\">\n <button class=\"btn btn-default btn-secondary\" type=\"button\" (click)=\"clearSearch($event)\">\n <i class=\"fa fa-times\"></i>\n </button>\n </div>\n </div>\n <a role=\"menuitem\" href=\"javascript:;\" tabindex=\"-1\" class=\"dropdown-item check-control check-control-check\" *ngIf=\"settings.showCheckAll && !disabledSelection && renderFilteredOptions.length > 1\"\n (click)=\"checkAll()\">\n <span style=\"width: 16px;\"><span [ngClass]=\"{'glyphicon glyphicon-ok': settings.checkedStyle !== 'fontawesome','fa fa-check': settings.checkedStyle === 'fontawesome'}\"></span></span>\n {{ texts.checkAll }}\n </a>\n <a role=\"menuitem\" href=\"javascript:;\" tabindex=\"-1\" class=\"dropdown-item check-control check-control-uncheck\" *ngIf=\"settings.showUncheckAll && !disabledSelection && renderFilteredOptions.length > 1\"\n (click)=\"uncheckAll()\">\n <span style=\"width: 16px;\"><span [ngClass]=\"{'glyphicon glyphicon-remove': settings.checkedStyle !== 'fontawesome','fa fa-times': settings.checkedStyle === 'fontawesome'}\"></span></span>\n {{ texts.uncheckAll }}\n </a>\n <a *ngIf=\"settings.showCheckAll || settings.showUncheckAll\" href=\"javascript:;\" class=\"dropdown-divider divider\"></a>\n <a *ngIf=\"!renderItems\" href=\"javascript:;\" class=\"dropdown-item empty\">{{ texts.searchNoRenderText }}</a>\n <a *ngIf=\"renderItems && !renderFilteredOptions.length\" href=\"javascript:;\" class=\"dropdown-item empty\">{{ texts.searchEmptyResult }}</a>\n <a class=\"dropdown-item\" href=\"javascript:;\" *ngFor=\"let option of renderFilteredOptions; trackBy: trackById\" [class.active]=\"isSelected(option)\"\n [ngStyle]=\"getItemStyle(option)\" [ngClass]=\"option.classes\" [class.dropdown-header]=\"option.isLabel\" [ssAutofocus]=\"option !== focusedItem\"\n tabindex=\"-1\" (click)=\"setSelected($event, option)\" (keydown.space)=\"setSelected($event, option)\" (keydown.enter)=\"setSelected($event, option)\">\n <span *ngIf=\"!option.isLabel; else label\" role=\"menuitem\" tabindex=\"-1\" [style.padding-left]=\"this.parents.length>0&&this.parents.indexOf(option.id)<0&&'30px'\"\n [ngStyle]=\"getItemStyleSelectionDisabled()\">\n <ng-container [ngSwitch]=\"settings.checkedStyle\">\n <input *ngSwitchCase=\"'checkboxes'\" type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"preventCheckboxCheck($event, option)\"\n [disabled]=\"isCheckboxDisabled(option)\" [ngStyle]=\"getItemStyleSelectionDisabled()\" />\n <span *ngSwitchCase=\"'glyphicon'\" style=\"width: 16px;\" class=\"glyphicon\" [class.glyphicon-ok]=\"isSelected(option)\" [class.glyphicon-lock]=\"isCheckboxDisabled(option)\"></span>\n <span *ngSwitchCase=\"'fontawesome'\" style=\"width: 16px;display: inline-block;\">\n <span *ngIf=\"isSelected(option)\"><i class=\"fa fa-check\" aria-hidden=\"true\"></i></span>\n <span *ngIf=\"isCheckboxDisabled(option)\"><i class=\"fa fa-lock\" aria-hidden=\"true\"></i></span>\n </span>\n <span *ngSwitchCase=\"'visual'\" style=\"display:block;float:left; border-radius: 0.2em; border: 0.1em solid rgba(44, 44, 44, 0.63);background:rgba(0, 0, 0, 0.1);width: 5.5em;\">\n <div class=\"slider\" [ngClass]=\"{'slideron': isSelected(option)}\">\n <img *ngIf=\"option.image != null\" [src]=\"option.image\" style=\"height: 100%; width: 100%; object-fit: contain\" />\n <div *ngIf=\"option.image == null\" style=\"height: 100%; width: 100%;text-align: center; display: table; background-color:rgba(0, 0, 0, 0.74)\">\n <div class=\"content_wrapper\">\n <span style=\"font-size:3em;color:white\" class=\"glyphicon glyphicon-eye-close\"></span>\n </div>\n </div>\n </div>\n </span>\n </ng-container>\n <span [ngClass]=\"{'chunkyrow': settings.checkedStyle == 'visual' }\" [class.disabled]=\"isCheckboxDisabled(option)\" [ngClass]=\"settings.itemClasses\"\n [style.font-weight]=\"this.parents.indexOf(option.id)>=0?'bold':'normal'\">\n {{ option.name }}\n </span>\n </span>\n <ng-template #label>\n <span [class.disabled]=\"isCheckboxDisabled(option)\">{{ option.name }}</span>\n </ng-template>\n </a>\n </div>\n</div>\n",
providers: [MULTISELECT_VALUE_ACCESSOR, MultiSelectSearchFilter],
changeDetection: ChangeDetectionStrategy.OnPush,
styles: ["a{outline:none!important}.dropdown-inline{display:inline-block}.dropdown-toggle .caret{display:inline-block;margin-left:4px;white-space:nowrap}.chunkydropdown-menu{min-width:20em}.chunkyrow{font-size:2em;line-height:2;margin-left:1em}.slider{display:block;height:3.8em;margin-left:.125em;margin-top:auto;transition:all .125s linear;width:3.8em}.slideron{margin-left:1.35em}.content_wrapper{display:table-cell;vertical-align:middle}.search-container{padding:0 5px 5px}"]
},] }
];
NgxDropdownMultiselectComponent.ctorParameters = () => [
{ type: FormBuilder },
{ type: MultiSelectSearchFilter },
{ type: IterableDiffers },
{ type: ChangeDetectorRef }
];
NgxDropdownMultiselectComponent.propDecorators = {
options: [{ type: Input }],
settings: [{ type: Input }],
texts: [{ type: Input }],
disabled: [{ type: Input }],
disabledSelection: [{ type: Input }],
searchFunction: [{ type: Input }],
selectionLimitReached: [{ type: Output }],
dropdownClosed: [{ type: Output }],
dropdownOpened: [{ type: Output }],
added: [{ type: Output }],
removed: [{ type: Output }],
lazyLoad: [{ type: Output }],
filter: [{ type: Output }]
};
class AutofocusDirective {
constructor(elemRef) {
this.elemRef = elemRef;
}
get element() {
return this.elemRef.nativeElement;
}
ngOnInit() {
this.focus();
}
ngOnChanges(changes) {
const ssAutofocusChange = changes.ssAutofocus;
if (ssAutofocusChange && !ssAutofocusChange.isFirstChange()) {
this.focus();
}
}
focus() {
if (this.ssAutofocus) {
return;
}
this.element.focus && this.element.focus();
}
}
AutofocusDirective.decorators = [
{ type: Directive, args: [{
selector: '[ssAutofocus]'
},] }
];
AutofocusDirective.ctorParameters = () => [
{ type: ElementRef, decorators: [{ type: Host }] }
];
AutofocusDirective.propDecorators = {
ssAutofocus: [{ type: Input }]
};
class OffClickDirective {
constructor() {
this.onOffClick = new EventEmitter();
}
onClick(event) {
this._clickEvent = event;
}
onTouch(event) {
this._touchEvent = event;
}
onDocumentClick(event) {
if (event !== this._clickEvent) {
this.onOffClick.emit(event);
}
}
onDocumentTouch(event) {
if (event !== this._touchEvent) {
this.onOffClick.emit(event);
}
}
}
OffClickDirective.decorators = [
{ type: Directive, args: [{
// tslint:disable-next-line:directive-selector
selector: '[offClick]',
},] }
];
OffClickDirective.propDecorators = {
onOffClick: [{ type: Output, args: ['offClick',] }],
onClick: [{ type: HostListener, args: ['click', ['$event'],] }],
onTouch: [{ type: HostListener, args: ['touchstart', ['$event'],] }],
onDocumentClick: [{ type: HostListener, args: ['document:click', ['$event'],] }],
onDocumentTouch: [{ type: HostListener, args: ['document:touchstart', ['$event'],] }]
};
class NgxBootstrapMultiselectModule {
}
NgxBootstrapMultiselectModule.decorators = [
{ type: NgModule, args: [{
declarations: [
NgxDropdownMultiselectComponent,
MultiSelectSearchFilter,
AutofocusDirective,
OffClickDirective
],
imports: [
CommonModule,
ReactiveFormsModule
],
exports: [
NgxDropdownMultiselectComponent,
MultiSelectSearchFilter,
],
},] }
];
/*
* Public API Surface of ngx-bootrap-multiselect
*/
/**
* Generated bundle index. Do not edit.
*/
export { MultiSelectSearchFilter, NgxBootstrapMultiselectModule, NgxDropdownMultiselectComponent, AutofocusDirective as ɵa, OffClickDirective as ɵb };
//# sourceMappingURL=ngx-bootrap-multiselect.js.map