@intzi1992/mat-table-filter
Version:
Provides filtering support for @angular/material tables
320 lines (309 loc) • 14.2 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Input, Host, Self, Optional, Directive, NgModule } from '@angular/core';
import * as i2 from '@angular/material/table';
import { MatTableModule } from '@angular/material/table';
import { BehaviorSubject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import isEqual from 'lodash-es/isEqual';
import cloneDeep from 'lodash-es/cloneDeep';
import isNil from 'lodash-es/isNil';
import every from 'lodash-es/every';
import isFunction from 'lodash-es/isFunction';
import isArray from 'lodash-es/isArray';
import isBoolean from 'lodash-es/isBoolean';
import isString from 'lodash-es/isString';
import isNumber from 'lodash-es/isNumber';
import isEmpty from 'lodash-es/isEmpty';
import difference from 'lodash-es/difference';
import flatten from 'lodash-es/flatten';
var MatTableFilter;
(function (MatTableFilter) {
MatTableFilter["EQUALS"] = "EQUALS";
MatTableFilter["ANYWHERE"] = "ANYWHERE";
MatTableFilter["STARTS_WITH"] = "STARTS_WITH";
MatTableFilter["ENDS_WITH"] = "ENDS_WITH";
})(MatTableFilter || (MatTableFilter = {}));
class FilterPredicate {
executeCondition(itemPair, options) {
this.handleLetterCasing(itemPair, options.caseSensitive);
switch (options.filterType) {
case MatTableFilter.EQUALS:
return this.equals(itemPair);
case MatTableFilter.ANYWHERE:
return this.anywhere(itemPair);
case MatTableFilter.STARTS_WITH:
return this.startsWith(itemPair);
case MatTableFilter.ENDS_WITH:
return this.endsWith(itemPair);
default:
return true;
}
}
handleLetterCasing(itemPair, caseSensitive) {
if (!caseSensitive) {
this.transformAllLowerCase(itemPair);
}
}
transformAllLowerCase(object) {
// tslint:disable-next-line:forin
for (const key in object) {
const value = object[key];
if (isString(value)) {
object[key] = value.toLowerCase();
}
else {
this.transformAllLowerCase(value);
}
}
}
}
class AlphaNumericPredicateService extends FilterPredicate {
constructor() {
super();
}
equals(itemPair) {
return itemPair.example === itemPair.item;
}
anywhere(itemPair) {
return itemPair.item.includes(itemPair.example);
}
startsWith(itemPair) {
return itemPair.item.startsWith(itemPair.example);
}
endsWith(itemPair) {
return itemPair.item.endsWith(itemPair.example);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlphaNumericPredicateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlphaNumericPredicateService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlphaNumericPredicateService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [] });
class ArrayPredicateService extends FilterPredicate {
// tslint:disable-next-line:max-line-length
static { this.UNSUPPORTED_OPERATION_WARNING = 'This filterType is unsupported for array filtering. FilterType.ANYWHERE is executed instead!'; }
static { this.SUGGESTION_WARNING = 'You can set a custom predicate for the array property through PropertyOptions!'; }
constructor() {
super();
}
static warn() {
console.warn(ArrayPredicateService.UNSUPPORTED_OPERATION_WARNING);
console.warn(ArrayPredicateService.SUGGESTION_WARNING);
}
equals(itemPair) {
return isEqual(itemPair.example.sort(), itemPair.item.sort());
}
anywhere(itemPair) {
return this.isSubset(itemPair.example, itemPair.item);
}
startsWith(itemPair) {
ArrayPredicateService.warn();
return this.anywhere(itemPair);
}
endsWith(itemPair) {
ArrayPredicateService.warn();
return this.anywhere(itemPair);
}
isSubset(example, item) {
return !difference(flatten(example), flatten(item)).length;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayPredicateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayPredicateService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayPredicateService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [] });
class MatTableFilterService {
constructor(_alphaNumericService, _arrayService) {
this._alphaNumericService = _alphaNumericService;
this._arrayService = _arrayService;
}
filterPredicate(itemPair, propertyOptions, commonOptions, propertyName) {
// tslint:disable-next-line:forin
const exampleKeys = Object.keys(itemPair.example);
for (const key of exampleKeys) {
const exampleValue = cloneDeep(itemPair.example[key]);
if (isNil(exampleValue) || every(exampleValue, isEmpty) && typeof exampleValue !== 'boolean') {
// if example entity's property is undefined/null/empty then it means the caller wants all the data
continue;
}
if (itemPair.item?.hasOwnProperty(key)) {
// if example entity has additional columns then search fails
const itemValue = cloneDeep(itemPair.item[key]);
const nextPropertyName = this.getNextPropertyName(key, propertyName);
const options = this.finalizeOptionsForProperty(commonOptions, propertyOptions, nextPropertyName);
if (isFunction(options)) { // if user defined predicate is present for property
const customPredicate = options;
if (!customPredicate(itemValue)) {
return false;
}
}
else {
const columnOptions = options;
if (this.isAlphaNumeric(itemValue)) {
const valuePair = { item: itemValue.toString(), example: exampleValue };
if (!this._alphaNumericService.executeCondition(valuePair, columnOptions)) {
return false;
}
}
else if (isArray(itemValue)) {
const valuePair = { item: itemValue, example: exampleValue };
if (!this._arrayService.executeCondition(valuePair, columnOptions)) {
return false;
}
}
else if (isBoolean(itemValue)) {
if (itemValue !== exampleValue) {
return false;
}
}
else {
const valuePair = { item: itemValue, example: exampleValue };
if (!this.filterPredicate(valuePair, propertyOptions, options, nextPropertyName)) {
// if one of the inner properties returns true, this shouldnt affect the whole item's filtering
// however if it returns false then the item must not be in the list
return false;
}
}
}
}
else {
return false;
}
}
return true;
}
finalizeOptionsForProperty(commonOptions, propertyOptions, propertyName) {
if (propertyOptions && propertyOptions.hasOwnProperty(propertyName)) {
return propertyOptions[propertyName];
}
else {
return commonOptions;
}
}
getNextPropertyName(key, propertyName) {
return propertyName ? (propertyName + '.' + key) : key;
}
isChanged(oldEntity, newEntity) {
return !isEqual(this.toPlainJson(oldEntity), this.toPlainJson(newEntity));
}
toPlainJson(object) {
if (!object)
return null;
return JSON.parse(JSON.stringify(object));
}
isAlphaNumeric(value) {
return isString(value) || isNumber(value);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterService, deps: [{ token: AlphaNumericPredicateService }, { token: ArrayPredicateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: AlphaNumericPredicateService }, { type: ArrayPredicateService }] });
class MatTableFilterDirective {
constructor(_filterService, _table) {
this._filterService = _filterService;
this._table = _table;
/**
* in millis
*/
this.debounceTime = 400;
this.filterType = MatTableFilter.ANYWHERE;
this.caseSensitive = false;
this.initDebounceSubject();
}
ngDoCheck() {
if (this._filterService.isChanged(this._oldExampleEntity, this.exampleEntity)) {
this._oldExampleEntity = this._filterService.toPlainJson(this.exampleEntity);
this._exampleEntitySubject.next(undefined);
}
}
initDebounceSubject() {
this._exampleEntitySubject = new BehaviorSubject(undefined);
this._exampleEntitySubject.pipe(debounceTime(this.debounceTime))
.subscribe(_ => {
this.updateFilterPredicate();
});
}
updateFilterPredicate() {
const matDataSource = this.getMatDataSource();
if (matDataSource) {
matDataSource.filterPredicate = this.getFilterPredicate();
matDataSource.filter = this.exampleEntity;
}
}
getFilterPredicate() {
if (this.customPredicate) {
return this.customPredicate;
}
else {
return (item) => {
return this._filterService.filterPredicate({ example: this.exampleEntity, item }, this.propertyOptions, { filterType: this.filterType, caseSensitive: this.caseSensitive });
};
}
}
getMatDataSource() {
const matTable = this._table;
return matTable.dataSource;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterDirective, deps: [{ token: MatTableFilterService }, { token: i2.MatTable, host: true, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: MatTableFilterDirective, selector: "[matTableFilter]", inputs: { exampleEntity: "exampleEntity", debounceTime: "debounceTime", filterType: "filterType", caseSensitive: "caseSensitive", customPredicate: "customPredicate", propertyOptions: "propertyOptions" }, exportAs: ["matTableFilter"], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterDirective, decorators: [{
type: Directive,
args: [{
selector: '[matTableFilter]',
exportAs: 'matTableFilter'
}]
}], ctorParameters: () => [{ type: MatTableFilterService }, { type: i2.MatTable, decorators: [{
type: Host
}, {
type: Self
}, {
type: Optional
}] }], propDecorators: { exampleEntity: [{
type: Input
}], debounceTime: [{
type: Input
}], filterType: [{
type: Input
}], caseSensitive: [{
type: Input
}], customPredicate: [{
type: Input
}], propertyOptions: [{
type: Input
}] } });
class MatTableFilterModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterModule, declarations: [MatTableFilterDirective], imports: [MatTableModule], exports: [MatTableFilterDirective] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterModule, imports: [MatTableModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatTableFilterModule, decorators: [{
type: NgModule,
args: [{
declarations: [MatTableFilterDirective],
imports: [
MatTableModule
],
exports: [MatTableFilterDirective]
}]
}] });
/*
* Public API Surface of mat-table-filter
*/
/**
* Generated bundle index. Do not edit.
*/
export { MatTableFilter, MatTableFilterDirective, MatTableFilterModule, MatTableFilterService };
//# sourceMappingURL=intzi1992-mat-table-filter.mjs.map