UNPKG

@devlukaszmichalak/mat-select-filter

Version:
181 lines (175 loc) 11.7 kB
import * as i0 from '@angular/core'; import { EventEmitter, Component, ViewChild, Input, Output, NgModule } from '@angular/core'; import * as i1 from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { A, Z, ZERO, NINE, SPACE } from '@angular/cdk/keycodes'; import { debounceTime, timer, take } from 'rxjs'; import * as i3 from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import * as i2 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i4 from '@angular/material/input'; import { MatInputModule } from '@angular/material/input'; class MatSelectFilterComponent { constructor(fb) { this.fb = fb; this.array = []; this.placeholder = 'Search...'; this.showSpinner = true; this.noResultsMessage = 'No results'; this.filterDebounceTime = 0; this.filteredReturn = new EventEmitter(); this.noResults = false; this.localSpinner = false; this.filteredItems = []; this.searchForm = this.fb.group({ value: '' }); } ngOnInit() { this.searchFormValueChangesSubscription = this.searchForm.valueChanges .pipe(debounceTime(this.filterDebounceTime)) .subscribe(value => { this.localSpinner = true; const userInputLowerCase = value['value'].toLowerCase(); if (userInputLowerCase) { this.filterArray(userInputLowerCase); // NO RESULTS VALIDATION this.noResults = this.filteredItems == null || this.filteredItems.length === 0; } else { this.filteredItems = this.array.slice(); this.noResults = false; } this.filteredReturn.emit(this.filteredItems); timer(2000) .pipe(take(1)) .subscribe(() => this.localSpinner = false); }); timer(500) .pipe(take(1)) .subscribe(() => this.input.nativeElement.focus()); } filterArray(userInputLowerCase) { // IF THE DISPLAY MEMBER INPUT IS SET WE CHECK THE SPECIFIC PROPERTY if (this.displayMember == null) { this.filteredItems = this.array.filter((name) => name.toLowerCase().includes(userInputLowerCase)); } else if (this.hasGroup && this.groupArrayName && this.displayMember) { this.filteredItems = this.array .map((a) => { const objCopy = { ...a }; objCopy[this.groupArrayName] = objCopy[this.groupArrayName].filter((g) => g[this.displayMember].toLowerCase().includes(userInputLowerCase)); return objCopy; }) .filter((x) => x[this.groupArrayName].length > 0); // OTHERWISE, WE CHECK THE ENTIRE STRING } else { this.filteredItems = this.array.filter((item) => item[this.displayMember].toLowerCase().includes(userInputLowerCase)); } } handleKeydown(event) { const isAlphanumeric = (event.key && event.key.length === 1) || (event.keyCode >= A && event.keyCode <= Z) || (event.keyCode >= ZERO && event.keyCode <= NINE) || (event.keyCode === SPACE); // PREVENT PROPAGATION FOR ALL ALPHANUMERIC CHARACTERS IN ORDER TO AVOID SELECTION ISSUES if (isAlphanumeric) { event.stopPropagation(); } } ngOnDestroy() { this.filteredReturn.emit(this.array); this.searchFormValueChangesSubscription.unsubscribe(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatSelectFilterComponent, deps: [{ token: i1.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.0", type: MatSelectFilterComponent, isStandalone: true, selector: "mat-select-filter", inputs: { array: "array", placeholder: "placeholder", color: "color", displayMember: "displayMember", showSpinner: "showSpinner", noResultsMessage: "noResultsMessage", hasGroup: "hasGroup", groupArrayName: "groupArrayName", filterDebounceTime: "filterDebounceTime" }, outputs: { filteredReturn: "filteredReturn" }, viewQueries: [{ propertyName: "input", first: true, predicate: ["input"], descendants: true, static: true }], ngImport: i0, template: ` <form [formGroup]="searchForm" class="mat-filter" [ngStyle]="{'background-color': color ? color : 'white'}"> <div> <input #input class="mat-filter-input" matInput placeholder="{{placeholder}}" formControlName="value" (keydown)="handleKeydown($event)"> <mat-spinner *ngIf="localSpinner && showSpinner" class="spinner" diameter="16"></mat-spinner> </div> <div *ngIf="noResults" class="noResultsMessage"> {{ noResultsMessage }} </div> </form> `, isInline: true, styles: [".mat-filter{position:sticky;top:-8px;margin-top:-8px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:gray;z-index:100;font-size:inherit;box-shadow:none;border-radius:0;padding:16px;-webkit-box-sizing:border-box;box-sizing:border-box}.mat-filter:has(.noResultsMessage){border:0}.mat-filter-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;border:0;background-color:unset;color:gray;width:100%}.spinner{position:absolute;right:16px;top:calc(50% - 8px)}.noResultsMessage{margin-top:16px;font-family:Roboto,Helvetica Neue,sans-serif;font-size:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatSelectFilterComponent, decorators: [{ type: Component, args: [{ selector: 'mat-select-filter', template: ` <form [formGroup]="searchForm" class="mat-filter" [ngStyle]="{'background-color': color ? color : 'white'}"> <div> <input #input class="mat-filter-input" matInput placeholder="{{placeholder}}" formControlName="value" (keydown)="handleKeydown($event)"> <mat-spinner *ngIf="localSpinner && showSpinner" class="spinner" diameter="16"></mat-spinner> </div> <div *ngIf="noResults" class="noResultsMessage"> {{ noResultsMessage }} </div> </form> `, imports: [ CommonModule, FormsModule, ReactiveFormsModule, MatProgressSpinnerModule, MatInputModule ], styles: [".mat-filter{position:sticky;top:-8px;margin-top:-8px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:gray;z-index:100;font-size:inherit;box-shadow:none;border-radius:0;padding:16px;-webkit-box-sizing:border-box;box-sizing:border-box}.mat-filter:has(.noResultsMessage){border:0}.mat-filter-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;border:0;background-color:unset;color:gray;width:100%}.spinner{position:absolute;right:16px;top:calc(50% - 8px)}.noResultsMessage{margin-top:16px;font-family:Roboto,Helvetica Neue,sans-serif;font-size:16px}\n"] }] }], ctorParameters: () => [{ type: i1.UntypedFormBuilder }], propDecorators: { input: [{ type: ViewChild, args: ['input', { static: true }] }], array: [{ type: Input, args: ['array'] }], placeholder: [{ type: Input, args: ['placeholder'] }], color: [{ type: Input, args: ['color'] }], displayMember: [{ type: Input, args: ['displayMember'] }], showSpinner: [{ type: Input, args: ['showSpinner'] }], noResultsMessage: [{ type: Input, args: ['noResultsMessage'] }], hasGroup: [{ type: Input, args: ['hasGroup'] }], groupArrayName: [{ type: Input, args: ['groupArrayName'] }], filterDebounceTime: [{ type: Input, args: ['filterDebounceTime'] }], filteredReturn: [{ type: Output }] } }); class MatSelectFilterModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatSelectFilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.0", ngImport: i0, type: MatSelectFilterModule, imports: [MatSelectFilterComponent], exports: [MatSelectFilterComponent] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatSelectFilterModule, imports: [MatSelectFilterComponent] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MatSelectFilterModule, decorators: [{ type: NgModule, args: [{ declarations: [], imports: [MatSelectFilterComponent], exports: [MatSelectFilterComponent] }] }] }); /* * Public API Surface of mat-select-filter */ /** * Generated bundle index. Do not edit. */ export { MatSelectFilterComponent, MatSelectFilterModule }; //# sourceMappingURL=devlukaszmichalak-mat-select-filter.mjs.map