mat-select-autocomplete
Version:
Angular material select component with autocomplete and select all features
337 lines (330 loc) • 10.7 kB
JavaScript
import { Injectable, NgModule, Component, EventEmitter, Input, Output, ViewChild, defineInjectable } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatIconModule } from '@angular/material/icon';
import { MatSelectModule } from '@angular/material/select';
import { MatFormFieldModule } from '@angular/material/form-field';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule, MatCheckboxModule } from '@angular/material';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class SelectAutocompleteService {
constructor() { }
}
SelectAutocompleteService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
SelectAutocompleteService.ctorParameters = () => [];
/** @nocollapse */ SelectAutocompleteService.ngInjectableDef = defineInjectable({ factory: function SelectAutocompleteService_Factory() { return new SelectAutocompleteService(); }, token: SelectAutocompleteService, providedIn: "root" });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class SelectAutocompleteComponent {
constructor() {
this.selectPlaceholder = "search...";
this.disabled = false;
this.display = "display";
this.value = "value";
this.formControl = new FormControl();
this.errorMsg = "Field is required";
this.showErrorMsg = false;
this.multiple = true;
// New Options
this.labelCount = 1;
this.appearance = "standard";
this.selectionChange = new EventEmitter();
this.filteredOptions = [];
this.selectedValue = [];
this.selectAllChecked = false;
this.displayString = "";
}
/**
* @return {?}
*/
ngOnChanges() {
if (this.disabled) {
this.formControl.disable();
}
else {
this.formControl.enable();
}
this.filteredOptions = this.options;
if (this.selectedOptions) {
this.selectedValue = this.selectedOptions;
}
else if (this.formControl.value) {
this.selectedValue = this.formControl.value;
}
}
/**
* @return {?}
*/
ngDoCheck() {
if (!this.selectedValue.length) {
this.selectionChange.emit(this.selectedValue);
}
}
/**
* @return {?}
*/
toggleDropdown() {
this.selectElem.toggle();
}
/**
* @param {?} val
* @return {?}
*/
toggleSelectAll(val) {
if (val.checked) {
this.filteredOptions.forEach(option => {
if (!this.selectedValue.includes(option[this.value])) {
this.selectedValue = this.selectedValue.concat([option[this.value]]);
}
});
}
else {
/** @type {?} */
const filteredValues = this.getFilteredOptionsValues();
this.selectedValue = this.selectedValue.filter(item => !filteredValues.includes(item));
}
this.selectionChange.emit(this.selectedValue);
}
/**
* @param {?} value
* @return {?}
*/
filterItem(value) {
this.filteredOptions = this.options.filter(item => item[this.display].toLowerCase().indexOf(value.toLowerCase()) > -1);
this.selectAllChecked = true;
this.filteredOptions.forEach(item => {
if (!this.selectedValue.includes(item[this.value])) {
this.selectAllChecked = false;
}
});
if (!this.filteredOptions.length) {
this.selectAllChecked = false;
}
}
/**
* @param {?} option
* @return {?}
*/
hideOption(option) {
return !(this.filteredOptions.indexOf(option) > -1);
}
/**
* @return {?}
*/
getFilteredOptionsValues() {
/** @type {?} */
const filteredValues = [];
this.filteredOptions.forEach(option => {
filteredValues.push(option.value);
});
return filteredValues;
}
/**
* @return {?}
*/
onDisplayString() {
this.displayString = "";
if (this.selectedValue && this.selectedValue.length) {
/** @type {?} */
let displayOption = [];
if (this.multiple) {
// Multi select display
for (let i = 0; i < this.labelCount; i++) {
displayOption[i] = this.options.filter(option => option[this.value] === this.selectedValue[i])[0];
}
if (displayOption.length) {
for (let i = 0; i < displayOption.length; i++) {
if (displayOption[i] && displayOption[i][this.display]) {
this.displayString += displayOption[i][this.display] + ",";
}
}
this.displayString = this.displayString.slice(0, -1);
if (this.selectedValue.length > 1 &&
this.selectedValue.length > this.labelCount) {
this.displayString += ` (+${this.selectedValue.length -
this.labelCount} others)`;
}
}
}
else {
// Single select display
displayOption = this.options.filter(option => option[this.value] === this.selectedValue);
if (displayOption.length) {
this.displayString = displayOption[0][this.display];
}
}
}
return this.displayString;
}
/**
* @param {?} val
* @return {?}
*/
onSelectionChange(val) {
/** @type {?} */
const filteredValues = this.getFilteredOptionsValues();
/** @type {?} */
let count = 0;
if (this.multiple) {
this.selectedValue.filter(item => {
if (filteredValues.includes(item)) {
count++;
}
});
this.selectAllChecked = count === this.filteredOptions.length;
}
this.selectedValue = val.value;
this.selectionChange.emit(this.selectedValue);
}
/**
* @param {?} index
* @param {?} item
* @return {?}
*/
trackByFn(index, item) {
return item.value;
}
}
SelectAutocompleteComponent.decorators = [
{ type: Component, args: [{
selector: "mat-select-autocomplete",
template: `
<mat-form-field appearance="{{ appearance }}">
<mat-select
#selectElem
[placeholder]="placeholder"
[formControl]="formControl"
[multiple]="multiple"
[(ngModel)]="selectedValue"
(selectionChange)="onSelectionChange($event)"
>
<div class="box-search">
<mat-checkbox
*ngIf="multiple"
color="primary"
class="box-select-all"
[(ngModel)]="selectAllChecked"
(change)="toggleSelectAll($event)"
></mat-checkbox>
<input
#searchInput
type="text"
[ngClass]="{ 'pl-1': !multiple }"
(input)="filterItem(searchInput.value)"
[placeholder]="selectPlaceholder"
/>
<div
class="box-search-icon"
(click)="filterItem(''); searchInput.value = ''"
>
<button mat-icon-button class="search-button">
<mat-icon class="mat-24" aria-label="Search icon">clear</mat-icon>
</button>
</div>
</div>
<mat-select-trigger>
{{ onDisplayString() }}
</mat-select-trigger>
<mat-option
*ngFor="let option of options; trackBy: trackByFn"
[disabled]="option.disabled"
[value]="option[value]"
[style.display]="hideOption(option) ? 'none' : 'flex'"
>{{ option[display] }}
</mat-option>
</mat-select>
<mat-hint style="color:red" *ngIf="showErrorMsg">{{ errorMsg }}</mat-hint>
</mat-form-field>
`,
styles: [`
.box-search {
margin: 8px;
border-radius: 2px;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16),
0 0 0 1px rgba(0, 0, 0, 0.08);
transition: box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
}
.box-search input {
flex: 1;
border: none;
outline: none;
}
.box-select-all {
width: 36px;
line-height: 33px;
color: #808080;
text-align: center;
}
.search-button {
width: 36px;
height: 36px;
line-height: 33px;
color: #808080;
}
.pl-1 {
padding-left: 1rem;
}
`]
}] }
];
/** @nocollapse */
SelectAutocompleteComponent.ctorParameters = () => [];
SelectAutocompleteComponent.propDecorators = {
selectPlaceholder: [{ type: Input }],
placeholder: [{ type: Input }],
options: [{ type: Input }],
disabled: [{ type: Input }],
display: [{ type: Input }],
value: [{ type: Input }],
formControl: [{ type: Input }],
errorMsg: [{ type: Input }],
showErrorMsg: [{ type: Input }],
selectedOptions: [{ type: Input }],
multiple: [{ type: Input }],
labelCount: [{ type: Input }],
appearance: [{ type: Input }],
selectionChange: [{ type: Output }],
selectElem: [{ type: ViewChild, args: ["selectElem",] }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class SelectAutocompleteModule {
}
SelectAutocompleteModule.decorators = [
{ type: NgModule, args: [{
imports: [
FormsModule,
CommonModule,
MatIconModule,
MatButtonModule,
MatSelectModule,
MatCheckboxModule,
MatFormFieldModule,
ReactiveFormsModule,
],
declarations: [SelectAutocompleteComponent],
exports: [SelectAutocompleteComponent]
},] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
export { SelectAutocompleteService, SelectAutocompleteComponent, SelectAutocompleteModule };
//# sourceMappingURL=mat-select-autocomplete.js.map