@progress/kendo-angular-filter
Version:
Kendo UI Angular Filter
1,053 lines (1,038 loc) • 120 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2026 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import * as i0 from '@angular/core';
import { Injectable, Directive, ContentChild, Input, Component, EventEmitter, Output, isDevMode, forwardRef, ViewChildren, ContentChildren, HostBinding, HostListener, NgModule } from '@angular/core';
import * as i1 from '@progress/kendo-angular-l10n';
import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
import { validatePackage } from '@progress/kendo-licensing';
import { Keys, TemplateContextDirective, normalizeKeys, ResizeBatchService } from '@progress/kendo-angular-common';
import { xIcon, filterAddGroupIcon, filterAddExpressionIcon } from '@progress/kendo-svg-icons';
import { ButtonComponent } from '@progress/kendo-angular-buttons';
import { DatePickerComponent, DatePickerCustomMessagesComponent, CalendarDOMService, CenturyViewService, DecadeViewService, MonthViewService, YearViewService, TimePickerDOMService, HoursService, MinutesService, SecondsService, MillisecondsService, DayPeriodService } from '@progress/kendo-angular-dateinputs';
import { DropDownListComponent, ValueTemplateDirective, ItemTemplateDirective } from '@progress/kendo-angular-dropdowns';
import { NumericTextBoxComponent, NumericTextBoxCustomMessagesComponent, TextBoxComponent } from '@progress/kendo-angular-inputs';
import { NgClass } from '@angular/common';
import { IconsService } from '@progress/kendo-angular-icons';
import { PopupService } from '@progress/kendo-angular-popup';
import { DialogContainerService, DialogService, WindowService, WindowContainerService, NavigationService as NavigationService$1 } from '@progress/kendo-angular-dialog';
/**
* @hidden
*/
class FilterService {
normalizedValue = { logic: 'and', filters: [] };
filters = [];
addFilterGroup(item) {
const filterGroup = { logic: 'and', filters: [] };
item.filters.push(filterGroup);
}
addFilterExpression(item) {
const filterExpression = { operator: 'eq', value: null, field: null };
item.filters.push(filterExpression);
}
remove(item, positionIndex, parentItem) {
if (!parentItem) {
parentItem = this.normalizedValue;
}
if (item === parentItem) {
parentItem.filters = [];
return;
}
const index = parentItem.filters.indexOf(item);
if (index >= 0 && index === positionIndex) {
parentItem.filters = parentItem.filters.filter((i) => i !== item);
return;
}
parentItem.filters.forEach((filter) => filter.filters && this.remove(item, positionIndex, filter));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterService, decorators: [{
type: Injectable
}] });
/**
* @hidden
*/
const nullOperators = ["isnull", "isnotnull", "isempty", "isnotempty"];
/**
* @hidden
*/
const numericOperators = [
{ text: "Is equal to", value: "eq" },
{ text: "Not equal to", value: "neq" },
{ text: "Greater than or equal to", value: "gte" },
{ text: "Greater than", value: "gt" },
{ text: "Less than or equal to", value: "lte" },
{ text: "Less than", value: "lt" },
{ text: "Is null", value: "isnull" },
{ text: "Is not null", value: "isnotnull" }
];
/**
* @hidden
*/
const stringOperators = [
{ text: "Is equal to", value: "eq" },
{ text: "Not equal to", value: "neq" },
{ text: "Contains", value: "contains" },
{ text: "Does not contain", value: "doesnotcontain" },
{ text: "Starts with", value: "startswith" },
{ text: "Ends with", value: "endswith" },
{ text: "Is null", value: "isnull" },
{ text: "Is not null", value: "isnotnull" },
{ text: "Is empty", value: "isempty" },
{ text: "Is not empty", value: "isnotempty" }
];
/**
* @hidden
*/
const booleanOperators = [
{ text: "Is equal to", value: "eq" },
{ text: "Is not equal to", value: "neq" }
];
/**
* @hidden
*/
const dateOperators = [
{ text: "Is equal to", value: "eq" },
{ text: "Not equal to", value: "neq" },
{ text: "Greater than or equal to", value: "gte" },
{ text: "Greater than", value: "gt" },
{ text: "Less than or equal to", value: "lte" },
{ text: "Less than", value: "lt" },
{ text: "Is null", value: "isnull" },
{ text: "Is not null", value: "isnotnull" }
];
/**
* @hidden
*/
const isArray = (value) => Array.isArray(value);
/**
* @hidden
*/
const getKeyByValue = (object, value) => {
return object && Object.keys(object).find(key => object[key] === value);
};
/**
* @hidden
*/
const defaultStringOperators = {
"filterEqOperator": "eq",
"filterNotEqOperator": "neq",
"filterContainsOperator": "contains",
"filterNotContainsOperator": "doesnotcontain",
"filterStartsWithOperator": "startswith",
"filterEndsWithOperator": "endswith",
"filterIsNullOperator": "isnull",
"filterIsNotNullOperator": "isnotnull",
"filterIsEmptyOperator": "isempty",
"filterIsNotEmptyOperator": "isnotempty"
};
/**
* @hidden
*/
const defaultNumericOperators = {
"filterEqOperator": "eq",
"filterNotEqOperator": "neq",
"filterGteOperator": "gte",
"filterGtOperator": "gt",
"filterLteOperator": "lte",
"filterLtOperator": "lt",
"filterIsNullOperator": "isnull",
"filterIsNotNullOperator": "isnotnull"
};
/**
* @hidden
*/
const defaultDateOperators = {
"filterEqOperator": "eq",
"filterNotEqOperator": "neq",
"filterAfterOrEqualOperator": "gte",
"filterAfterOperator": "gt",
"filterBeforeOrEqualOperator": "lte",
"filterBeforeOperator": "lt",
"filterIsNullOperator": "isnull",
"filterIsNotNullOperator": "isnotnull"
};
/**
* @hidden
*/
const defaultOperators = {
"string": defaultStringOperators,
"number": defaultNumericOperators,
"date": defaultDateOperators
};
/**
* @hidden
*/
const logicOperators = {
"filterAndLogic": 'and',
"filterOrLogic": 'or'
};
/**
* @hidden
*/
const isFilterEditor = (editorType) => {
const supportedEditorTypes = ['string', 'number', 'boolean', 'date'];
return supportedEditorTypes.indexOf(editorType) >= 0;
};
/**
* @hidden
*/
const localizeOperators = operators => localization => Object.keys(operators).map(key => ({
text: localization.get(key),
value: operators[key]
}));
/**
* @hidden
*/
const isPresent = (value) => value !== null && value !== undefined;
/**
* @hidden
*/
class FilterItem {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterItem, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterItem });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterItem, decorators: [{
type: Injectable
}] });
/**
* @hidden
*/
const selectors = {
andButton: `button.k-group-start`,
orButton: `button.k-group-end`,
addFilterButton: `button[icon="filter-add-expression"]`,
addGroupButton: `button[icon="filter-add-group"]`,
removeButton: `button[icon="x"]`,
filterFieldWrapper: `.k-filter-field`,
filterOperatorWrapper: `.k-filter-operator`,
filterValueEditorWrapper: `.k-filter-value`,
kendoDropDownListComponent: `kendo-dropdownlist`,
kendoInput: `.k-input`,
kendoInputInner: `.k-input-inner`,
inputElement: `input`,
textAreaElement: `textarea`,
kendoToolbar: `.k-toolbar`,
kendoButton: `.k-button`,
kendoFilterToolbarItem: `.k-toolbar-item`,
kendoFilterToolbarButton: `.k-toolbar-button`
};
/**
* @hidden
*/
const packageMetadata = {
name: '@progress/kendo-angular-filter',
productName: 'Kendo UI for Angular',
productCode: 'KENDOUIANGULAR',
productCodes: ['KENDOUIANGULAR'],
publishDate: 0,
version: '22.0.1',
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
};
/**
* Directive for providing a custom value editor template in the Filter component.
* Used as a structural directive to customize the filter value editor UI.
*
* @example
* ```html
* <ng-template kendoFilterValueEditorTemplate let-value>
* <!-- custom editor markup -->
* </ng-template>
* ```
*/
class FilterValueEditorTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterValueEditorTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.18", type: FilterValueEditorTemplateDirective, isStandalone: true, selector: "[kendoFilterValueEditorTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterValueEditorTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoFilterValueEditorTemplate]',
standalone: true
}]
}], ctorParameters: () => [{ type: i0.TemplateRef }] });
/**
* Represents the [Kendo UI Filter Field component for Angular]({% slug api_filter_filterfieldcomponent %}).
* Used to declare filter expressions for the Filter component.
*
* @example
* ```html
* <kendo-filter>
* <kendo-filter-field field="country" editor="string" [operators]="['neq', 'eq', 'contains']"></kendo-filter-field>
* <kendo-filter-field field="budget" editor="number"></kendo-filter-field>
* <kendo-filter-field field="discontinued" title="Discontinued" editor="boolean"></kendo-filter-field>
* <kendo-filter-field field="ordered on" title="Ordered on" editor="date"></kendo-filter-field>
* <kendo-filter>
* ```
*/
class FilterFieldComponent {
/**
* Specifies the `field` that will be used by the user-defined filter.
*/
field;
/**
* Specifies the `title` text that will be displayed by the user-defined filter.
* If the `title` isn't set, the value passed to `field` is used.
*/
set title(_title) {
if (_title) {
this._title = _title;
}
else {
this._title = this.field;
}
}
get title() {
return this._title;
}
_title;
/**
* Specifies the user-defined filter `editor` type that will be used.
* The available options are 'string', 'number', 'boolean', and 'date'.
*/
editor;
/**
* Specifies the operators that will be available in the order of providing them.
* If no operators are provided, default operators are used for each filter type.
*
* The default string operators are:
* * `eq`— Is equal to
* * `neq`— Is not equal to
* * `isnull`— Is null
* * `isnotnull`— Is not null
* * `contains`— Contains
* * `doesnotcontain`— Does not contain
* * `startswith`— Starts with
* * `endswith`— Ends with
* * `isempty`— Is empty
* * `isnotempty`— Is not empty
*
* The default number and date operators are:
* * `eq`— Is equals to
* * `neq`— Is not equal to
* * `isnull`— Is null
* * `isnotnull`— Is not null
* * `gt`— Greater than
* * `gte`— Greater than or equal to
* * `lt`— Less than
* * `lte`— Less than or equal to
*
* The boolean operator is always set to `eq`
*/
operators;
/**
* Specifies the user-defined filter `editor` format that will be used. ([see example]({% slug filter_editor_formats %}))
*/
editorFormat;
/**
* @hidden
*/
editorTemplate;
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.18", type: FilterFieldComponent, isStandalone: true, selector: "kendo-filter-field", inputs: { field: "field", title: "title", editor: "editor", operators: "operators", editorFormat: "editorFormat" }, queries: [{ propertyName: "editorTemplate", first: true, predicate: FilterValueEditorTemplateDirective, descendants: true }], ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterFieldComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-filter-field',
template: ``,
standalone: true
}]
}], propDecorators: { field: [{
type: Input
}], title: [{
type: Input
}], editor: [{
type: Input
}], operators: [{
type: Input
}], editorFormat: [{
type: Input
}], editorTemplate: [{
type: ContentChild,
args: [FilterValueEditorTemplateDirective]
}] } });
/**
* @hidden
*/
class NavigationService {
cdr;
renderer;
hierarchicalFilterItems = [];
flattenFilterItems = [];
currentToolbarItemIndex = 0;
currentToolbarItemChildrenIndex = 0;
isFilterNavigationActivated = true;
isFilterExpressionComponentFocused = false;
currentlyFocusedElement;
constructor(cdr, renderer) {
this.cdr = cdr;
this.renderer = renderer;
}
processKeyDown(key, event) {
switch (key) {
case Keys.ArrowUp: {
event.preventDefault();
if (!this.isFilterExpressionComponentFocused) {
this.currentToolbarItemChildrenIndex = 0;
if (this.currentToolbarItemIndex > 0) {
this.currentToolbarItemIndex--;
}
const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[0];
this.focusCurrentElement(elementToFocus);
}
break;
}
case Keys.ArrowDown: {
event.preventDefault();
if (!this.isFilterExpressionComponentFocused) {
this.currentToolbarItemChildrenIndex = 0;
if (this.currentToolbarItemIndex < this.flattenFilterItems.length - 1) {
this.currentToolbarItemIndex++;
}
const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[0];
this.focusCurrentElement(elementToFocus);
}
break;
}
case Keys.NumpadEnter:
case Keys.Enter: {
const isEventTargetKendoFilterToolbarItem = event.target.closest(selectors.kendoFilterToolbarItem);
const isEventTargetButton = event.target.closest(selectors.kendoButton);
if (this.isFilterNavigationActivated &&
!this.isFilterExpressionComponentFocused &&
isEventTargetKendoFilterToolbarItem &&
!isEventTargetButton) {
event.preventDefault();
this.isFilterExpressionComponentFocused = true;
const focusableElement = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
const elementToFocus = focusableElement.querySelector(selectors.KendoDropDownListComponent) ||
focusableElement.querySelector(selectors.kendoInputInner) ||
focusableElement.querySelector(selectors.inputElement) ||
focusableElement.querySelector(selectors.textAreaElement);
this.focusCurrentElement(elementToFocus);
}
break;
}
case Keys.Escape: {
if (this.isFilterExpressionComponentFocused) {
event.preventDefault();
this.isFilterExpressionComponentFocused = false;
const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
this.focusCurrentElement(elementToFocus);
}
break;
}
case Keys.ArrowRight: {
if (this.isFilterNavigationActivated && !this.isFilterExpressionComponentFocused) {
event.preventDefault();
if (this.currentToolbarItemChildrenIndex < this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren.length - 1) {
this.currentToolbarItemChildrenIndex++;
}
const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
this.focusCurrentElement(elementToFocus);
}
break;
}
case Keys.ArrowLeft: {
if (this.isFilterNavigationActivated && !this.isFilterExpressionComponentFocused) {
event.preventDefault();
if (this.currentToolbarItemChildrenIndex > 0) {
this.currentToolbarItemChildrenIndex--;
}
const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
this.focusCurrentElement(elementToFocus);
}
break;
}
default:
break;
}
}
focusCurrentElement(element, isOnMouseDown) {
this.renderer.setAttribute(this.currentlyFocusedElement, 'tabindex', '-1');
this.currentlyFocusedElement = element;
if (element) {
this.renderer.setAttribute(this.currentlyFocusedElement, 'tabindex', '0');
if (!isOnMouseDown) {
this.currentlyFocusedElement.focus();
}
}
}
flattenHierarchicalFilterItems(filterItems) {
filterItems.forEach((filterRow) => {
const flattenItem = { component: filterRow, isGroup: false, toolbarElement: filterRow.toolbarElement, focusableChildren: [] };
this.flattenFilterItems.push(flattenItem);
if ((filterRow['operators'] && filterRow['filterItems']?.length > 0)) {
this.setGroupItemChildren(flattenItem, filterRow);
this.flattenHierarchicalFilterItems(filterRow['filterItems']);
}
else if (filterRow['operators'] && filterRow['filterItems']?.length === 0) {
this.setGroupItemChildren(flattenItem, filterRow);
}
else {
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.filterFieldWrapper));
if (filterRow.toolbarElement.querySelector('.k-filter-operator')) {
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.filterOperatorWrapper));
}
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.filterValueEditorWrapper));
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.removeButton));
}
});
}
setGroupItemChildren(flattenItem, filterRow) {
flattenItem.isGroup = true;
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.andButton));
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.orButton));
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.addFilterButton));
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.addGroupButton));
flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.removeButton));
}
setItemIndexes() {
this.flattenFilterItems.forEach((item, index) => {
item.component['itemNumber'] = index;
});
this.cdr.detectChanges();
}
reset(items) {
this.flattenFilterItems = [];
this.hierarchicalFilterItems = items;
this.flattenHierarchicalFilterItems(items);
this.setItemIndexes();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: NavigationService, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: NavigationService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: NavigationService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }] });
/**
* @hidden
*/
const FilterErrorMessages = {
missingFilters: `Pass at least one user-defined filter through the [filters] input property or nest kendo-filter-field components. See https://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`,
missingFilterForUsedField: (field) => `There is no user-defined filter with '${field}' field provided through the [filters] input property.`,
missingValueForBooleanField: (field) => `Provide a value for the boolean '${field}' user-defined filter as the operator is always set to 'eq'.`,
operatorBooleanField: (field) => `The operator of the boolean '${field}' user-defined filter is always set to 'eq'.`,
filterMissingUsedOperator: (field, operator) => `The user-defined filter with field '${field}' is missing the '${operator}' operator.`,
improperNumericEditorValue: (title) => `The provided value for the numeric editor of the '${title}' filter expression isn't one of a supported type string or NumberFormat. See https://www.telerik.com/kendo-angular-ui/components/filter/#editor-formats/`,
improperDateEditorValue: (title) => `The provided value for the date editor of the '${title}' filter expression isn't one of a supported type string or DateFormat. See https://www.telerik.com/kendo-angular-ui/components/filter/#editor-formats/`
};
/**
* @hidden
*/
class BaseFilterRowComponent {
element;
navigationService;
localization;
renderer;
index;
valueChange = new EventEmitter();
constructor(element, navigationService, localization, renderer) {
this.element = element;
this.navigationService = navigationService;
this.localization = localization;
this.renderer = renderer;
}
itemNumber = 0;
get toolbarElement() {
return this.element.nativeElement.querySelector('.k-toolbar');
}
messageFor(key) {
return this.localization.get(key);
}
onMouseDown(event) {
let elementToFocus;
const closestFilterToolbarItem = event.target.closest(selectors.kendoFilterToolbarItem);
const closestButton = event.target.closest(selectors.kendoFilterToolbarButton);
const closestToolbarItem = event.target.closest(selectors.kendoToolbar);
if (closestFilterToolbarItem || closestButton) {
const index = Array.from(closestToolbarItem.children).indexOf(closestFilterToolbarItem) > -1
? Array.from(closestToolbarItem.children).indexOf(closestFilterToolbarItem)
: Array.from(closestToolbarItem.children).indexOf(closestButton);
this.navigationService.currentToolbarItemChildrenIndex = index;
this.navigationService.isFilterNavigationActivated = true;
this.navigationService.isFilterExpressionComponentFocused = true;
const wrapperElement = this.navigationService.flattenFilterItems[this.itemNumber].focusableChildren[index];
elementToFocus = wrapperElement.querySelector(selectors.kendoDropDownListComponent) ||
wrapperElement.querySelector(selectors.kendoInput) ||
wrapperElement.querySelector(selectors.kendoInputInner) ||
wrapperElement.querySelector(selectors.inputElement) ||
wrapperElement.querySelector(selectors.textAreaElement) ||
wrapperElement.querySelector(selectors.kendoButton) ||
wrapperElement;
}
else {
this.navigationService.currentToolbarItemChildrenIndex = 0;
this.navigationService.isFilterNavigationActivated = false;
this.navigationService.isFilterExpressionComponentFocused = false;
elementToFocus = this.navigationService.flattenFilterItems[this.itemNumber].focusableChildren[0];
}
this.navigationService.currentToolbarItemIndex = this.itemNumber;
this.navigationService.focusCurrentElement(elementToFocus, true);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: BaseFilterRowComponent, deps: [{ token: i0.ElementRef }, { token: NavigationService }, { token: i1.LocalizationService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.18", type: BaseFilterRowComponent, isStandalone: true, inputs: { index: "index" }, outputs: { valueChange: "valueChange" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: BaseFilterRowComponent, decorators: [{
type: Directive,
args: [{}]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: NavigationService }, { type: i1.LocalizationService }, { type: i0.Renderer2 }], propDecorators: { index: [{
type: Input
}], valueChange: [{
type: Output
}] } });
/**
* @hidden
*/
class AriaLabelValueDirective {
hostElement;
renderer;
ariaLabel;
constructor(hostElement, renderer) {
this.hostElement = hostElement;
this.renderer = renderer;
}
ngOnInit() {
const target = this.hostElement.nativeElement.querySelector('input') || this.hostElement.nativeElement;
this.renderer.setAttribute(target, 'aria-label', this.ariaLabel);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: AriaLabelValueDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.18", type: AriaLabelValueDirective, isStandalone: true, selector: "[kendoAriaLabelValue]", inputs: { ariaLabel: ["kendoAriaLabelValue", "ariaLabel"] }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: AriaLabelValueDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoAriaLabelValue]',
standalone: true
}]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { ariaLabel: [{
type: Input,
args: ['kendoAriaLabelValue']
}] } });
/**
* @hidden
*/
class FilterDateEditorComponent {
localization;
currentItem;
isDisabled;
format;
valueChange = new EventEmitter();
constructor(localization) {
this.localization = localization;
}
messageFor(key) {
return this.localization.get(key);
}
onValueChange(value) {
this.currentItem.value = value;
this.valueChange.emit();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterDateEditorComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.18", type: FilterDateEditorComponent, isStandalone: true, selector: "kendo-filter-date-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled", format: "format" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
<kendo-datepicker
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
[value]="currentItem.value"
(valueChange)="onValueChange($event)"
[disabled]="isDisabled"
[format]="format">
<kendo-datepicker-messages
[toggle]="messageFor('editorDateToggleText')"
[today]="messageFor('editorDateTodayText')">
</kendo-datepicker-messages>
</kendo-datepicker>
`, isInline: true, dependencies: [{ kind: "component", type: DatePickerComponent, selector: "kendo-datepicker", inputs: ["focusableId", "cellTemplate", "clearButton", "inputAttributes", "monthCellTemplate", "yearCellTemplate", "decadeCellTemplate", "centuryCellTemplate", "weekNumberTemplate", "headerTitleTemplate", "headerTemplate", "footerTemplate", "footer", "navigationItemTemplate", "weekDaysFormat", "showOtherMonthDays", "activeView", "bottomView", "topView", "calendarType", "animateCalendarNavigation", "disabled", "readonly", "readOnlyInput", "popupSettings", "navigation", "min", "max", "incompleteDateValidation", "autoCorrectParts", "autoSwitchParts", "autoSwitchKeys", "enableMouseWheel", "allowCaretMode", "autoFill", "focusedDate", "value", "format", "twoDigitYearMax", "formatPlaceholder", "placeholder", "tabindex", "tabIndex", "disabledDates", "adaptiveTitle", "adaptiveSubtitle", "rangeValidation", "disabledDatesValidation", "weekNumber", "size", "rounded", "fillMode", "adaptiveMode"], outputs: ["valueChange", "focus", "blur", "open", "close", "escape"], exportAs: ["kendo-datepicker"] }, { kind: "directive", type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }, { kind: "component", type: DatePickerCustomMessagesComponent, selector: "kendo-datepicker-messages" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterDateEditorComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-filter-date-editor',
template: `
<kendo-datepicker
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
[value]="currentItem.value"
(valueChange)="onValueChange($event)"
[disabled]="isDisabled"
[format]="format">
<kendo-datepicker-messages
[toggle]="messageFor('editorDateToggleText')"
[today]="messageFor('editorDateTodayText')">
</kendo-datepicker-messages>
</kendo-datepicker>
`,
standalone: true,
imports: [DatePickerComponent, AriaLabelValueDirective, DatePickerCustomMessagesComponent]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }], propDecorators: { currentItem: [{
type: Input
}], isDisabled: [{
type: Input
}], format: [{
type: Input
}], valueChange: [{
type: Output
}] } });
/**
* @hidden
*/
class FilterBooleanEditorComponent {
localization;
cdr;
currentItem;
valueChange = new EventEmitter();
items;
defaultItem;
localizationSubscription;
constructor(localization, cdr) {
this.localization = localization;
this.cdr = cdr;
}
ngOnInit() {
this.localizationSubscription = this.localization.changes.subscribe(() => {
this.defaultItem = this.getDefaultItem();
this.items = this.getValueItems();
this.cdr.detectChanges();
});
this.items = this.getValueItems();
this.defaultItem = this.getDefaultItem();
}
getDefaultItem() {
return { text: this.localization.get("filterBooleanAll"), value: null };
}
getValueItems() {
return [
{ text: this.localization.get("filterIsTrue"), value: true },
{ text: this.localization.get("filterIsFalse"), value: false }
];
}
ngOnDestroy() {
if (this.localizationSubscription) {
this.localizationSubscription.unsubscribe();
}
}
messageFor(key) {
return this.localization.get(key);
}
onValueChange(value) {
this.currentItem.value = value;
this.valueChange.emit();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterBooleanEditorComponent, deps: [{ token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.18", type: FilterBooleanEditorComponent, isStandalone: true, selector: "kendo-filter-boolean-editor", inputs: { currentItem: "currentItem" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
<kendo-dropdownlist
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
[value]="currentItem.value"
(valueChange)="onValueChange($event)"
[data]="items"
[defaultItem]="defaultItem"
[valuePrimitive]="true"
textField="text"
valueField="value"
>
</kendo-dropdownlist>
`, isInline: true, dependencies: [{ kind: "component", type: DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "directive", type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterBooleanEditorComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-filter-boolean-editor',
template: `
<kendo-dropdownlist
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
[value]="currentItem.value"
(valueChange)="onValueChange($event)"
[data]="items"
[defaultItem]="defaultItem"
[valuePrimitive]="true"
textField="text"
valueField="value"
>
</kendo-dropdownlist>
`,
standalone: true,
imports: [DropDownListComponent, AriaLabelValueDirective]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }], propDecorators: { currentItem: [{
type: Input
}], valueChange: [{
type: Output
}] } });
/**
* @hidden
*/
class FilterNumericEditorComponent {
localization;
currentItem;
isDisabled;
format;
valueChange = new EventEmitter();
constructor(localization) {
this.localization = localization;
}
messageFor(key) {
return this.localization.get(key);
}
onValueChange(value) {
this.currentItem.value = value;
this.valueChange.emit();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterNumericEditorComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.18", type: FilterNumericEditorComponent, isStandalone: true, selector: "kendo-filter-numeric-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled", format: "format" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
<kendo-numerictextbox
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
[value]="currentItem.value"
(valueChange)="onValueChange($event)"
[disabled]="isDisabled"
[format]="format">
<kendo-numerictextbox-messages
[increment]="messageFor('editorNumericIncrement')"
[decrement]="messageFor('editorNumericDecrement')">
</kendo-numerictextbox-messages>
</kendo-numerictextbox>
`, isInline: true, dependencies: [{ kind: "component", type: NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "directive", type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }, { kind: "component", type: NumericTextBoxCustomMessagesComponent, selector: "kendo-numerictextbox-messages" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterNumericEditorComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-filter-numeric-editor',
template: `
<kendo-numerictextbox
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
[value]="currentItem.value"
(valueChange)="onValueChange($event)"
[disabled]="isDisabled"
[format]="format">
<kendo-numerictextbox-messages
[increment]="messageFor('editorNumericIncrement')"
[decrement]="messageFor('editorNumericDecrement')">
</kendo-numerictextbox-messages>
</kendo-numerictextbox>
`,
standalone: true,
imports: [NumericTextBoxComponent, AriaLabelValueDirective, NumericTextBoxCustomMessagesComponent]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }], propDecorators: { currentItem: [{
type: Input
}], isDisabled: [{
type: Input
}], format: [{
type: Input
}], valueChange: [{
type: Output
}] } });
/**
* @hidden
*/
class FilterTextEditorComponent {
localization;
currentItem;
isDisabled;
valueChange = new EventEmitter();
constructor(localization) {
this.localization = localization;
}
messageFor(key) {
return this.localization.get(key);
}
onValueChange(value) {
this.currentItem.value = value;
this.valueChange.emit();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterTextEditorComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.18", type: FilterTextEditorComponent, isStandalone: true, selector: "kendo-filter-text-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
<kendo-textbox
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
[value]="currentItem.value"
(valueChange)="onValueChange($event)"
[disabled]="isDisabled">
</kendo-textbox>
`, isInline: true, dependencies: [{ kind: "component", type: TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "directive", type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterTextEditorComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-filter-text-editor',
template: `
<kendo-textbox
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
[value]="currentItem.value"
(valueChange)="onValueChange($event)"
[disabled]="isDisabled">
</kendo-textbox>
`,
standalone: true,
imports: [TextBoxComponent, AriaLabelValueDirective]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }], propDecorators: { currentItem: [{
type: Input
}], isDisabled: [{
type: Input
}], valueChange: [{
type: Output
}] } });
/**
* @hidden
*/
class FilterExpressionOperatorsComponent {
localization;
currentItem;
editorType;
valueChange = new EventEmitter();
operators = [];
constructor(localization) {
this.localization = localization;
}
messageFor(key) {
return this.localization.get(key);
}
getOperator(operatorValue) {
return this.messageFor(getKeyByValue(defaultOperators[this.editorType], operatorValue));
}
operatorValueChange(value) {
this.valueChange.emit(value);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterExpressionOperatorsComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.18", type: FilterExpressionOperatorsComponent, isStandalone: true, selector: "kendo-filter-expression-operators", inputs: { currentItem: "currentItem", editorType: "editorType", operators: "operators" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
<kendo-dropdownlist
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterOperatorAriaLabel')"
[data]="operators"
[title]="messageFor('filterExpressionOperators')"
[(value)]="currentItem.operator"
(valueChange)="operatorValueChange($event)"
[valuePrimitive]="true"
textField="text"
valueField="value"
>
<ng-template kendoDropDownListValueTemplate let-dataItem>
<span>{{ getOperator(dataItem.value) }}</span>
</ng-template>
<ng-template kendoDropDownListItemTemplate let-dataItem>
<span>{{ getOperator(dataItem.value) }}</span>
</ng-template>
</kendo-dropdownlist>
`, isInline: true, dependencies: [{ kind: "component", type: DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "directive", type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }, { kind: "directive", type: ValueTemplateDirective, selector: "[kendoDropDownListValueTemplate],[kendoDropDownTreeValueTemplate]" }, { kind: "directive", type: ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: FilterExpressionOperatorsComponent, decorators: [{
type: Component,
args: [{
selector: "kendo-filter-expression-operators",
template: `
<kendo-dropdownlist
[tabindex]="-1"
[kendoAriaLabelValue]="messageFor('filterOperatorAriaLabel')"
[data]="operators"
[title]="messageFor('filterExpressionOperators')"
[(value)]="currentItem.operator"
(valueChange)="operatorValueChange($event)"
[valuePrimitive]="true"
textField="text"
valueField="value"
>
<ng-template kendoDropDownListValueTemplate let-dataItem>
<span>{{ getOperator(dataItem.value) }}</span>
</ng-template>
<ng-template kendoDropDownListItemTemplate let-dataItem>
<span>{{ getOperator(dataItem.value) }}</span>
</ng-template>
</kendo-dropdownlist>
`,
standalone: true,
imports: [DropDownListComponent, AriaLabelValueDirective, ValueTemplateDirective, ItemTemplateDirective]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }], propDecorators: { currentItem: [{
type: Input
}], editorType: [{
type: Input
}], valueChange: [{
type: Output
}], operators: [{
type: Input
}] } });
/**
* @hidden
*/
class FilterExpressionComponent extends BaseFilterRowComponent {
filterService;
cdr;
/**
* @hidden
*/
xIcon = xIcon;
static ngAcceptInputType_currentItem;
currentItem;
operators = [];
isBoolean = false;
editorType;
isEditorDisabled = false;
editorTemplate;
editorFormat;
get currentFilterExpression() {
return this.getFilterExpressionByField(this.currentItem.field);
}
get numericEditorFormat() {
const isSupportedFormat = typeof this.editorFormat !== 'string' && !this.isNumberFormat(this.editorFormat);
if (this.editorFormat && isSupportedFormat) {
console.warn(FilterErrorMessages.improperNumericEditorValue(this.currentFilterExpression.title));
}
return this.editorFormat;
}
get dateEditorFormat() {
const isSupportedFormat = typeof this.editorFormat !== 'string' && !this.isDateFormat(this.editorFormat);
if (this.editorFormat && isSupportedFormat) {
console.warn(FilterErrorMessages.improperDateEditorValue(this.currentFilterExpression.title));
}
return this.editorFormat;
}
isNumberFormat(obj) {
if (isDevMode() && obj &&
(obj['currency'] ||
obj['currencyDisplay'] ||
obj['maximumFractionDigits'] ||
obj['minimumIntegerDigits'] ||
obj['style'] ||
obj['useGrouping'])) {
return true;
}
else {
return false;
}
}
isDateFormat(obj) {
if (isDevMode() && obj && obj['displayFormat'] && obj['inputFormat']) {
return true;
}
else {
return false;
}
}
localizationSubscription;
constructor(filterService, cdr, element, navigationService, localization, renderer) {
super(element, navigationService, localization, renderer);
this.filterService = filterService;
this.cdr = cdr;
}
ngOnInit() {
this.isEditorDisabled = nullOperators.indexOf(this.currentItem.operator) >= 0;
const foundFilter = this.getFilterExpressionByField(this.currentItem.field);
if (this.currentItem.field) {
this.setOperators(foundFilter);
}
if (foundFilter?.editorFormat) {
this.editorFormat = foundFilter.editorForma