@progress/kendo-angular-filter 2.0.1-dev.202205191247 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,12 +2,13 @@
2
2
  * Copyright © 2021 Progress Software Corporation. All rights reserved.
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
- import { Component, Input, Output, EventEmitter, HostBinding, isDevMode } from '@angular/core';
5
+ import { Component, Input, Output, EventEmitter, HostBinding, isDevMode, ContentChildren } from '@angular/core';
6
6
  import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n';
7
7
  import { FilterService } from './filter.service';
8
- import { isArray, nullOperators, isPresent } from './util';
8
+ import { nullOperators, isPresent } from './util';
9
9
  import { validatePackage } from '@progress/kendo-licensing';
10
10
  import { packageMetadata } from './package-metadata';
11
+ import { FilterFieldComponent } from './filter-field.component';
11
12
  import * as i0 from "@angular/core";
12
13
  import * as i1 from "./filter.service";
13
14
  import * as i2 from "@progress/kendo-angular-l10n";
@@ -63,17 +64,16 @@ export class FilterComponent {
63
64
  * Specifies the available user-defined filters. At least one filter should be provided.
64
65
  */
65
66
  set filters(_filters) {
66
- if (isDevMode() && (!isArray(_filters) || _filters.length === 0)) {
67
- throw new Error(`Pass at least one user-defined filter through the [filters] input property. See http://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`);
67
+ if (_filters.length > 0) {
68
+ this.filterService.filters = _filters.map(filterExpression => {
69
+ let clonedFilter = Object.assign({}, filterExpression);
70
+ if (!clonedFilter.title) {
71
+ clonedFilter.title = clonedFilter.field;
72
+ }
73
+ return clonedFilter;
74
+ });
75
+ this.setValue(this.value);
68
76
  }
69
- this.filterService.filters = _filters.map(filterExpression => {
70
- let clonedFilter = Object.assign({}, filterExpression);
71
- if (!clonedFilter.title) {
72
- clonedFilter.title = clonedFilter.field;
73
- }
74
- return clonedFilter;
75
- });
76
- this.setValue(this.value);
77
77
  }
78
78
  get filters() {
79
79
  return this.filterService.filters;
@@ -84,20 +84,30 @@ export class FilterComponent {
84
84
  set value(value) {
85
85
  const clonedValue = JSON.parse(JSON.stringify(value));
86
86
  this._value = clonedValue;
87
- this.setValue(this.value);
87
+ if (this.filters.length > 0) {
88
+ this.setValue(this.value);
89
+ }
88
90
  }
89
91
  get value() {
90
92
  return this._value;
91
93
  }
92
94
  ngOnInit() {
93
- if (this.filters.length === 0) {
94
- throw new Error(`Pass at least one user-defined filter through the [filters] input property. See http://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`);
95
- }
96
95
  this.localizationSubscription = this.localization.changes.subscribe(({ rtl }) => {
97
96
  this.direction = rtl ? 'rtl' : 'ltr';
98
97
  this.cdr.detectChanges();
99
98
  });
100
99
  }
100
+ ngAfterViewChecked() {
101
+ if (this.filterFields && this.filterFields.length > 0) {
102
+ this.filters = this.filterFields.map((filterField) => {
103
+ var _a;
104
+ return (Object.assign(Object.assign({}, filterField), { editorTemplate: (_a = filterField.editorTemplate) === null || _a === void 0 ? void 0 : _a.templateRef }));
105
+ });
106
+ }
107
+ if (this.filters.length === 0) {
108
+ throw new Error(`Pass at least one user-defined filter through the [filters] input property or nest kendo-filter-field components. See http://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`);
109
+ }
110
+ }
101
111
  ngOnDestroy() {
102
112
  if (this.localizationSubscription) {
103
113
  this.localizationSubscription.unsubscribe();
@@ -123,6 +133,9 @@ export class FilterComponent {
123
133
  if (isDevMode() && foundFilter.editor === 'boolean' && (!filterDescriptor.value && filterDescriptor.value !== false)) {
124
134
  console.warn(`Provide a value for the boolean '${filterDescriptor.field}' user-defined filter as the operator is always set to 'eq'.`);
125
135
  }
136
+ if (isDevMode() && foundFilter.editor === 'boolean' && filterDescriptor.operator !== 'eq') {
137
+ console.warn(`The operator of the boolean '${filterDescriptor.field}' user-defined filter is always set to 'eq'.`);
138
+ }
126
139
  if (filterDescriptor.operator && foundFilter.operators && !foundFilter.operators.some(operator => operator === filterDescriptor.operator)) {
127
140
  throw new Error(`The user-defined filter with field '${filterDescriptor.field}' is missing the '${filterDescriptor.operator}' operator.`);
128
141
  }
@@ -165,7 +178,7 @@ FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
165
178
  useValue: 'kendo.filter'
166
179
  },
167
180
  FilterService
168
- ], ngImport: i0, template: `
181
+ ], queries: [{ propertyName: "filterFields", predicate: FilterFieldComponent }], ngImport: i0, template: `
169
182
  <ng-container kendoFilterLocalizedMessages
170
183
  i18n-editorDateTodayText="kendo.filter.editorDateTodayText|The text of the Today button of the Date editor"
171
184
  editorDateTodayText="Today"
@@ -439,4 +452,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
439
452
  type: Input
440
453
  }], valueChange: [{
441
454
  type: Output
455
+ }], filterFields: [{
456
+ type: ContentChildren,
457
+ args: [FilterFieldComponent]
442
458
  }] } });
@@ -10,11 +10,13 @@ import { FilterNumericEditorComponent } from './editors/numeric-editor.component
10
10
  import { FilterTextEditorComponent } from './editors/text-editor.component';
11
11
  import { FilterExpressionOperatorsComponent } from './filter-expression-operators.component';
12
12
  import { FilterExpressionComponent } from './filter-expression.component';
13
+ import { FilterFieldComponent } from './filter-field.component';
13
14
  import { FilterGroupComponent } from './filter-group.component';
14
15
  import { FilterComponent } from './filter.component';
15
16
  import { CustomMessagesComponent } from './localization/custom-messages.component';
16
17
  import { LocalizedMessagesDirective } from './localization/localized-messages.directive';
17
18
  import { SharedModule } from './shared.module';
19
+ import { FilterValueEditorTemplateDirective } from './templates/value-editor.template';
18
20
  import * as i0 from "@angular/core";
19
21
  /**
20
22
  * Represents the [NgModule]({{ site.data.urls.angular['ngmoduleapi'] }})
@@ -60,7 +62,9 @@ FilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "
60
62
  FilterDateEditorComponent,
61
63
  LocalizedMessagesDirective,
62
64
  CustomMessagesComponent,
63
- AriaLabelValueDirective], imports: [SharedModule], exports: [FilterComponent,
65
+ AriaLabelValueDirective,
66
+ FilterFieldComponent,
67
+ FilterValueEditorTemplateDirective], imports: [SharedModule], exports: [FilterComponent,
64
68
  FilterNumericEditorComponent,
65
69
  FilterTextEditorComponent,
66
70
  FilterExpressionComponent,
@@ -70,7 +74,9 @@ FilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "
70
74
  FilterDateEditorComponent,
71
75
  LocalizedMessagesDirective,
72
76
  CustomMessagesComponent,
73
- AriaLabelValueDirective] });
77
+ AriaLabelValueDirective,
78
+ FilterFieldComponent,
79
+ FilterValueEditorTemplateDirective] });
74
80
  FilterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterModule, imports: [[SharedModule]] });
75
81
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterModule, decorators: [{
76
82
  type: NgModule,
@@ -86,7 +92,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
86
92
  FilterDateEditorComponent,
87
93
  LocalizedMessagesDirective,
88
94
  CustomMessagesComponent,
89
- AriaLabelValueDirective
95
+ AriaLabelValueDirective,
96
+ FilterFieldComponent,
97
+ FilterValueEditorTemplateDirective
90
98
  ],
91
99
  exports: [FilterComponent,
92
100
  FilterNumericEditorComponent,
@@ -98,6 +106,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
98
106
  FilterDateEditorComponent,
99
107
  LocalizedMessagesDirective,
100
108
  CustomMessagesComponent,
101
- AriaLabelValueDirective]
109
+ AriaLabelValueDirective,
110
+ FilterFieldComponent,
111
+ FilterValueEditorTemplateDirective]
102
112
  }]
103
113
  }] });
@@ -9,10 +9,11 @@ import * as i0 from "@angular/core";
9
9
  */
10
10
  export class FilterService {
11
11
  constructor() {
12
+ this.normalizedValue = { logic: 'and', filters: [] };
12
13
  this.filters = [];
13
14
  }
14
15
  addFilterGroup(item) {
15
- let filterGroup = { logic: 'or', filters: [] };
16
+ let filterGroup = { logic: 'and', filters: [] };
16
17
  item.filters.push(filterGroup);
17
18
  }
18
19
  addFilterExpression(item) {
package/esm2015/main.js CHANGED
@@ -14,3 +14,5 @@ export { FilterExpressionOperatorsComponent } from './filter-expression-operator
14
14
  export { FilterExpressionComponent } from './filter-expression.component';
15
15
  export { CustomMessagesComponent } from './localization/custom-messages.component';
16
16
  export { LocalizedMessagesDirective } from './localization/localized-messages.directive';
17
+ export { FilterFieldComponent } from './filter-field.component';
18
+ export { FilterValueEditorTemplateDirective } from './templates/value-editor.template';
@@ -9,7 +9,7 @@ export const packageMetadata = {
9
9
  name: '@progress/kendo-angular-filter',
10
10
  productName: 'Kendo UI for Angular',
11
11
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
12
- publishDate: 1652964392,
12
+ publishDate: 1655825197,
13
13
  version: '',
14
14
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning'
15
15
  };
@@ -0,0 +1,19 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2021 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { Directive } from '@angular/core';
6
+ import * as i0 from "@angular/core";
7
+ export class FilterValueEditorTemplateDirective {
8
+ constructor(templateRef) {
9
+ this.templateRef = templateRef;
10
+ }
11
+ }
12
+ FilterValueEditorTemplateDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterValueEditorTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
13
+ FilterValueEditorTemplateDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: FilterValueEditorTemplateDirective, selector: "[kendoFilterValueEditorTemplate]", ngImport: i0 });
14
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterValueEditorTemplateDirective, decorators: [{
15
+ type: Directive,
16
+ args: [{
17
+ selector: '[kendoFilterValueEditorTemplate]'
18
+ }]
19
+ }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
@@ -3,7 +3,7 @@
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import * as i0 from '@angular/core';
6
- import { Injectable, Directive, Input, EventEmitter, Component, Output, forwardRef, isDevMode, HostBinding, NgModule } from '@angular/core';
6
+ import { Injectable, Directive, Component, Input, ContentChild, EventEmitter, Output, forwardRef, isDevMode, HostBinding, ContentChildren, NgModule } from '@angular/core';
7
7
  import * as i1 from '@progress/kendo-angular-l10n';
8
8
  import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
9
9
  import { validatePackage } from '@progress/kendo-licensing';
@@ -24,10 +24,11 @@ import { LabelModule } from '@progress/kendo-angular-label';
24
24
  */
25
25
  class FilterService {
26
26
  constructor() {
27
+ this.normalizedValue = { logic: 'and', filters: [] };
27
28
  this.filters = [];
28
29
  }
29
30
  addFilterGroup(item) {
30
- let filterGroup = { logic: 'or', filters: [] };
31
+ let filterGroup = { logic: 'and', filters: [] };
31
32
  item.filters.push(filterGroup);
32
33
  }
33
34
  addFilterExpression(item) {
@@ -200,11 +201,86 @@ const packageMetadata = {
200
201
  name: '@progress/kendo-angular-filter',
201
202
  productName: 'Kendo UI for Angular',
202
203
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
203
- publishDate: 1652964392,
204
+ publishDate: 1655825197,
204
205
  version: '',
205
206
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning'
206
207
  };
207
208
 
209
+ class FilterValueEditorTemplateDirective {
210
+ constructor(templateRef) {
211
+ this.templateRef = templateRef;
212
+ }
213
+ }
214
+ FilterValueEditorTemplateDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterValueEditorTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
215
+ FilterValueEditorTemplateDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: FilterValueEditorTemplateDirective, selector: "[kendoFilterValueEditorTemplate]", ngImport: i0 });
216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterValueEditorTemplateDirective, decorators: [{
217
+ type: Directive,
218
+ args: [{
219
+ selector: '[kendoFilterValueEditorTemplate]'
220
+ }]
221
+ }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
222
+
223
+ /**
224
+ * Represents the [Kendo UI Filter Field component for Angular]({% slug api_filter_filterfieldcomponent %}).
225
+ * The Filter Field component can be used to add Filter Expressions declaratively.
226
+ * @example
227
+ * ```
228
+ * @Component({
229
+ * selector: 'my-app',
230
+ * template: `
231
+ * <kendo-filter (valueChange)="onValueChange($event)">
232
+ * <kendo-filter-field field="country" editor="string" [operators]="['neq', 'eq', 'contains']"></kendo-filter-field>
233
+ * <kendo-filter-field field="budget" editor="number"></kendo-filter-field>
234
+ * <kendo-filter-field field="discontinued" title="Discontinued" editor="boolean"></kendo-filter-field>
235
+ * <kendo-filter-field field="ordered on" title="Ordered on" editor="date"></kendo-filter-field>
236
+ * <kendo-filter>
237
+ * `
238
+ * })
239
+ * export class AppComponent {
240
+ * onValueChange(e: CompositeFilterDescriptor){
241
+ * console.log(e)
242
+ * }
243
+ * }
244
+ * ```
245
+ */
246
+ class FilterFieldComponent {
247
+ /**
248
+ * Specifies the `title` text that will be displayed by the user-defined filter.
249
+ * If the `title` isn't set, the value passed to `field` is used.
250
+ */
251
+ set title(_title) {
252
+ if (_title) {
253
+ this._title = _title;
254
+ }
255
+ else {
256
+ this._title = this.field;
257
+ }
258
+ }
259
+ get title() {
260
+ return this._title;
261
+ }
262
+ }
263
+ FilterFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
264
+ FilterFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterFieldComponent, selector: "kendo-filter-field", inputs: { field: "field", title: "title", editor: "editor", operators: "operators" }, queries: [{ propertyName: "editorTemplate", first: true, predicate: FilterValueEditorTemplateDirective, descendants: true }], ngImport: i0, template: ``, isInline: true });
265
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterFieldComponent, decorators: [{
266
+ type: Component,
267
+ args: [{
268
+ selector: 'kendo-filter-field',
269
+ template: ``
270
+ }]
271
+ }], propDecorators: { field: [{
272
+ type: Input
273
+ }], title: [{
274
+ type: Input
275
+ }], editor: [{
276
+ type: Input
277
+ }], operators: [{
278
+ type: Input
279
+ }], editorTemplate: [{
280
+ type: ContentChild,
281
+ args: [FilterValueEditorTemplateDirective]
282
+ }] } });
283
+
208
284
  /**
209
285
  * @hidden
210
286
  */
@@ -317,7 +393,6 @@ FilterTextEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0"
317
393
  FilterTextEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterTextEditorComponent, selector: "kendo-filter-text-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
318
394
  <kendo-textbox
319
395
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
320
- class="k-filter-toolbar-item k-filter-value"
321
396
  [(value)]="currentItem.value"
322
397
  (valueChange)="valueChange.emit()"
323
398
  [disabled]="isDisabled">
@@ -330,7 +405,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
330
405
  template: `
331
406
  <kendo-textbox
332
407
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
333
- class="k-filter-toolbar-item k-filter-value"
334
408
  [(value)]="currentItem.value"
335
409
  (valueChange)="valueChange.emit()"
336
410
  [disabled]="isDisabled">
@@ -361,7 +435,6 @@ FilterNumericEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0
361
435
  FilterNumericEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterNumericEditorComponent, selector: "kendo-filter-numeric-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
362
436
  <kendo-numerictextbox
363
437
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
364
- class="k-filter-toolbar-item k-filter-value"
365
438
  [(value)]="currentItem.value"
366
439
  (valueChange)="valueChange.emit()"
367
440
  [disabled]="isDisabled">
@@ -378,7 +451,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
378
451
  template: `
379
452
  <kendo-numerictextbox
380
453
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
381
- class="k-filter-toolbar-item k-filter-value"
382
454
  [(value)]="currentItem.value"
383
455
  (valueChange)="valueChange.emit()"
384
456
  [disabled]="isDisabled">
@@ -437,7 +509,6 @@ FilterBooleanEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0
437
509
  FilterBooleanEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterBooleanEditorComponent, selector: "kendo-filter-boolean-editor", inputs: { currentItem: "currentItem" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
438
510
  <kendo-dropdownlist
439
511
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
440
- class="k-filter-toolbar-item k-filter-value"
441
512
  [(value)]="currentItem.value"
442
513
  (valueChange)="valueChange.emit()"
443
514
  [data]="items"
@@ -455,7 +526,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
455
526
  template: `
456
527
  <kendo-dropdownlist
457
528
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
458
- class="k-filter-toolbar-item k-filter-value"
459
529
  [(value)]="currentItem.value"
460
530
  (valueChange)="valueChange.emit()"
461
531
  [data]="items"
@@ -489,7 +559,6 @@ FilterDateEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0"
489
559
  FilterDateEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterDateEditorComponent, selector: "kendo-filter-date-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
490
560
  <kendo-datepicker
491
561
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
492
- class="k-filter-toolbar-item k-filter-value"
493
562
  [(value)]="currentItem.value"
494
563
  (valueChange)="valueChange.emit()"
495
564
  [disabled]="isDisabled">
@@ -506,7 +575,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
506
575
  template: `
507
576
  <kendo-datepicker
508
577
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
509
- class="k-filter-toolbar-item k-filter-value"
510
578
  [(value)]="currentItem.value"
511
579
  (valueChange)="valueChange.emit()"
512
580
  [disabled]="isDisabled">
@@ -551,6 +619,7 @@ class FilterExpressionComponent {
551
619
  this.currentItem.field = this.filterService.filters[0].field;
552
620
  this.setOperators(defaultFilter);
553
621
  }
622
+ this.setEditorTemplate();
554
623
  this.localizationSubscription = this.localization.changes.subscribe(() => {
555
624
  this.setOperators(foundFilter || defaultFilter);
556
625
  this.cdr.detectChanges();
@@ -586,6 +655,7 @@ class FilterExpressionComponent {
586
655
  filterValueChange(value) {
587
656
  this.currentItem.value = null;
588
657
  this.currentItem.field = value;
658
+ this.setEditorTemplate();
589
659
  const foundFilter = this.getFilterExpressionByField(this.currentItem.field);
590
660
  this.setOperators(foundFilter);
591
661
  this.valueChange.emit();
@@ -639,6 +709,12 @@ class FilterExpressionComponent {
639
709
  this.isEditorDisabled = false;
640
710
  }
641
711
  }
712
+ setEditorTemplate() {
713
+ let filterExpression = this.filterService.filters.find((filter) => filter.field === this.currentItem.field);
714
+ if (filterExpression.editorTemplate) {
715
+ this.editorTemplate = filterExpression.editorTemplate;
716
+ }
717
+ }
642
718
  }
643
719
  FilterExpressionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionComponent, deps: [{ token: FilterService }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
644
720
  FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterExpressionComponent, selector: "kendo-filter-expression", inputs: { index: "index", currentItem: "currentItem" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
@@ -665,12 +741,19 @@ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.
665
741
  </kendo-filter-expression-operators>
666
742
  </div>
667
743
 
668
- <ng-container [ngSwitch]="getEditorType()">
669
- <kendo-filter-text-editor *ngSwitchCase="'string'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-text-editor>
670
- <kendo-filter-numeric-editor *ngSwitchCase="'number'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-numeric-editor>
671
- <kendo-filter-boolean-editor *ngSwitchCase="'boolean'" [currentItem]="currentItem" (valueChange)="valueChange.emit()"></kendo-filter-boolean-editor>
672
- <kendo-filter-date-editor *ngSwitchCase="'date'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-date-editor>
673
- </ng-container>
744
+ <div class="k-filter-toolbar-item k-filter-value">
745
+ <ng-container *ngIf="!editorTemplate" [ngSwitch]="getEditorType()">
746
+ <kendo-filter-text-editor *ngSwitchCase="'string'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-text-editor>
747
+ <kendo-filter-numeric-editor *ngSwitchCase="'number'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-numeric-editor>
748
+ <kendo-filter-boolean-editor *ngSwitchCase="'boolean'" [currentItem]="currentItem" (valueChange)="valueChange.emit()"></kendo-filter-boolean-editor>
749
+ <kendo-filter-date-editor *ngSwitchCase="'date'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-date-editor>
750
+ </ng-container>
751
+ <ng-container *ngIf="editorTemplate">
752
+ <ng-template
753
+ [templateContext]="{templateRef: editorTemplate, $implicit: currentItem}">
754
+ </ng-template>
755
+ </ng-container>
756
+ </div>
674
757
 
675
758
  <div class="k-filter-toolbar-item">
676
759
  <button
@@ -683,7 +766,7 @@ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.
683
766
  </div>
684
767
  </div>
685
768
  </div>
686
- `, isInline: true, components: [{ type: i2.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["iconClass", "loading", "data", "value", "textField", "valueField", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { type: FilterExpressionOperatorsComponent, selector: "kendo-filter-expression-operators", inputs: ["currentItem", "editorType", "operators"], outputs: ["valueChange"] }, { type: FilterTextEditorComponent, selector: "kendo-filter-text-editor", inputs: ["currentItem", "isDisabled"], outputs: ["valueChange"] }, { type: FilterNumericEditorComponent, selector: "kendo-filter-numeric-editor", inputs: ["currentItem", "isDisabled"], outputs: ["valueChange"] }, { type: FilterBooleanEditorComponent, selector: "kendo-filter-boolean-editor", inputs: ["currentItem"], outputs: ["valueChange"] }, { type: FilterDateEditorComponent, selector: "kendo-filter-date-editor", inputs: ["currentItem", "isDisabled"], outputs: ["valueChange"] }], directives: [{ type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i11.ButtonDirective, selector: "button[kendoButton], span[kendoButton]", inputs: ["toggleable", "togglable", "selected", "tabIndex", "icon", "iconClass", "imageUrl", "disabled", "size", "rounded", "fillMode", "themeColor", "role", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
769
+ `, isInline: true, components: [{ type: i2.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["iconClass", "loading", "data", "value", "textField", "valueField", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { type: FilterExpressionOperatorsComponent, selector: "kendo-filter-expression-operators", inputs: ["currentItem", "editorType", "operators"], outputs: ["valueChange"] }, { type: FilterTextEditorComponent, selector: "kendo-filter-text-editor", inputs: ["currentItem", "isDisabled"], outputs: ["valueChange"] }, { type: FilterNumericEditorComponent, selector: "kendo-filter-numeric-editor", inputs: ["currentItem", "isDisabled"], outputs: ["valueChange"] }, { type: FilterBooleanEditorComponent, selector: "kendo-filter-boolean-editor", inputs: ["currentItem"], outputs: ["valueChange"] }, { type: FilterDateEditorComponent, selector: "kendo-filter-date-editor", inputs: ["currentItem", "isDisabled"], outputs: ["valueChange"] }], directives: [{ type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i11.TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { type: i11.ButtonDirective, selector: "button[kendoButton], span[kendoButton]", inputs: ["toggleable", "togglable", "selected", "tabIndex", "icon", "iconClass", "imageUrl", "disabled", "size", "rounded", "fillMode", "themeColor", "role", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
687
770
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionComponent, decorators: [{
688
771
  type: Component,
689
772
  args: [{
@@ -712,12 +795,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
712
795
  </kendo-filter-expression-operators>
713
796
  </div>
714
797
 
715
- <ng-container [ngSwitch]="getEditorType()">
716
- <kendo-filter-text-editor *ngSwitchCase="'string'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-text-editor>
717
- <kendo-filter-numeric-editor *ngSwitchCase="'number'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-numeric-editor>
718
- <kendo-filter-boolean-editor *ngSwitchCase="'boolean'" [currentItem]="currentItem" (valueChange)="valueChange.emit()"></kendo-filter-boolean-editor>
719
- <kendo-filter-date-editor *ngSwitchCase="'date'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-date-editor>
720
- </ng-container>
798
+ <div class="k-filter-toolbar-item k-filter-value">
799
+ <ng-container *ngIf="!editorTemplate" [ngSwitch]="getEditorType()">
800
+ <kendo-filter-text-editor *ngSwitchCase="'string'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-text-editor>
801
+ <kendo-filter-numeric-editor *ngSwitchCase="'number'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-numeric-editor>
802
+ <kendo-filter-boolean-editor *ngSwitchCase="'boolean'" [currentItem]="currentItem" (valueChange)="valueChange.emit()"></kendo-filter-boolean-editor>
803
+ <kendo-filter-date-editor *ngSwitchCase="'date'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-date-editor>
804
+ </ng-container>
805
+ <ng-container *ngIf="editorTemplate">
806
+ <ng-template
807
+ [templateContext]="{templateRef: editorTemplate, $implicit: currentItem}">
808
+ </ng-template>
809
+ </ng-container>
810
+ </div>
721
811
 
722
812
  <div class="k-filter-toolbar-item">
723
813
  <button
@@ -1105,17 +1195,16 @@ class FilterComponent {
1105
1195
  * Specifies the available user-defined filters. At least one filter should be provided.
1106
1196
  */
1107
1197
  set filters(_filters) {
1108
- if (isDevMode() && (!isArray(_filters) || _filters.length === 0)) {
1109
- throw new Error(`Pass at least one user-defined filter through the [filters] input property. See http://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`);
1198
+ if (_filters.length > 0) {
1199
+ this.filterService.filters = _filters.map(filterExpression => {
1200
+ let clonedFilter = Object.assign({}, filterExpression);
1201
+ if (!clonedFilter.title) {
1202
+ clonedFilter.title = clonedFilter.field;
1203
+ }
1204
+ return clonedFilter;
1205
+ });
1206
+ this.setValue(this.value);
1110
1207
  }
1111
- this.filterService.filters = _filters.map(filterExpression => {
1112
- let clonedFilter = Object.assign({}, filterExpression);
1113
- if (!clonedFilter.title) {
1114
- clonedFilter.title = clonedFilter.field;
1115
- }
1116
- return clonedFilter;
1117
- });
1118
- this.setValue(this.value);
1119
1208
  }
1120
1209
  get filters() {
1121
1210
  return this.filterService.filters;
@@ -1126,20 +1215,30 @@ class FilterComponent {
1126
1215
  set value(value) {
1127
1216
  const clonedValue = JSON.parse(JSON.stringify(value));
1128
1217
  this._value = clonedValue;
1129
- this.setValue(this.value);
1218
+ if (this.filters.length > 0) {
1219
+ this.setValue(this.value);
1220
+ }
1130
1221
  }
1131
1222
  get value() {
1132
1223
  return this._value;
1133
1224
  }
1134
1225
  ngOnInit() {
1135
- if (this.filters.length === 0) {
1136
- throw new Error(`Pass at least one user-defined filter through the [filters] input property. See http://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`);
1137
- }
1138
1226
  this.localizationSubscription = this.localization.changes.subscribe(({ rtl }) => {
1139
1227
  this.direction = rtl ? 'rtl' : 'ltr';
1140
1228
  this.cdr.detectChanges();
1141
1229
  });
1142
1230
  }
1231
+ ngAfterViewChecked() {
1232
+ if (this.filterFields && this.filterFields.length > 0) {
1233
+ this.filters = this.filterFields.map((filterField) => {
1234
+ var _a;
1235
+ return (Object.assign(Object.assign({}, filterField), { editorTemplate: (_a = filterField.editorTemplate) === null || _a === void 0 ? void 0 : _a.templateRef }));
1236
+ });
1237
+ }
1238
+ if (this.filters.length === 0) {
1239
+ throw new Error(`Pass at least one user-defined filter through the [filters] input property or nest kendo-filter-field components. See http://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`);
1240
+ }
1241
+ }
1143
1242
  ngOnDestroy() {
1144
1243
  if (this.localizationSubscription) {
1145
1244
  this.localizationSubscription.unsubscribe();
@@ -1165,6 +1264,9 @@ class FilterComponent {
1165
1264
  if (isDevMode() && foundFilter.editor === 'boolean' && (!filterDescriptor.value && filterDescriptor.value !== false)) {
1166
1265
  console.warn(`Provide a value for the boolean '${filterDescriptor.field}' user-defined filter as the operator is always set to 'eq'.`);
1167
1266
  }
1267
+ if (isDevMode() && foundFilter.editor === 'boolean' && filterDescriptor.operator !== 'eq') {
1268
+ console.warn(`The operator of the boolean '${filterDescriptor.field}' user-defined filter is always set to 'eq'.`);
1269
+ }
1168
1270
  if (filterDescriptor.operator && foundFilter.operators && !foundFilter.operators.some(operator => operator === filterDescriptor.operator)) {
1169
1271
  throw new Error(`The user-defined filter with field '${filterDescriptor.field}' is missing the '${filterDescriptor.operator}' operator.`);
1170
1272
  }
@@ -1207,7 +1309,7 @@ FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
1207
1309
  useValue: 'kendo.filter'
1208
1310
  },
1209
1311
  FilterService
1210
- ], ngImport: i0, template: `
1312
+ ], queries: [{ propertyName: "filterFields", predicate: FilterFieldComponent }], ngImport: i0, template: `
1211
1313
  <ng-container kendoFilterLocalizedMessages
1212
1314
  i18n-editorDateTodayText="kendo.filter.editorDateTodayText|The text of the Today button of the Date editor"
1213
1315
  editorDateTodayText="Today"
@@ -1481,6 +1583,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1481
1583
  type: Input
1482
1584
  }], valueChange: [{
1483
1585
  type: Output
1586
+ }], filterFields: [{
1587
+ type: ContentChildren,
1588
+ args: [FilterFieldComponent]
1484
1589
  }] } });
1485
1590
 
1486
1591
  /**
@@ -1600,7 +1705,9 @@ FilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "
1600
1705
  FilterDateEditorComponent,
1601
1706
  LocalizedMessagesDirective,
1602
1707
  CustomMessagesComponent,
1603
- AriaLabelValueDirective], imports: [SharedModule], exports: [FilterComponent,
1708
+ AriaLabelValueDirective,
1709
+ FilterFieldComponent,
1710
+ FilterValueEditorTemplateDirective], imports: [SharedModule], exports: [FilterComponent,
1604
1711
  FilterNumericEditorComponent,
1605
1712
  FilterTextEditorComponent,
1606
1713
  FilterExpressionComponent,
@@ -1610,7 +1717,9 @@ FilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "
1610
1717
  FilterDateEditorComponent,
1611
1718
  LocalizedMessagesDirective,
1612
1719
  CustomMessagesComponent,
1613
- AriaLabelValueDirective] });
1720
+ AriaLabelValueDirective,
1721
+ FilterFieldComponent,
1722
+ FilterValueEditorTemplateDirective] });
1614
1723
  FilterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterModule, imports: [[SharedModule]] });
1615
1724
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterModule, decorators: [{
1616
1725
  type: NgModule,
@@ -1626,7 +1735,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1626
1735
  FilterDateEditorComponent,
1627
1736
  LocalizedMessagesDirective,
1628
1737
  CustomMessagesComponent,
1629
- AriaLabelValueDirective
1738
+ AriaLabelValueDirective,
1739
+ FilterFieldComponent,
1740
+ FilterValueEditorTemplateDirective
1630
1741
  ],
1631
1742
  exports: [FilterComponent,
1632
1743
  FilterNumericEditorComponent,
@@ -1638,7 +1749,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1638
1749
  FilterDateEditorComponent,
1639
1750
  LocalizedMessagesDirective,
1640
1751
  CustomMessagesComponent,
1641
- AriaLabelValueDirective]
1752
+ AriaLabelValueDirective,
1753
+ FilterFieldComponent,
1754
+ FilterValueEditorTemplateDirective]
1642
1755
  }]
1643
1756
  }] });
1644
1757
 
@@ -1646,5 +1759,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1646
1759
  * Generated bundle index. Do not edit.
1647
1760
  */
1648
1761
 
1649
- export { AriaLabelValueDirective, CustomMessagesComponent, FilterBooleanEditorComponent, FilterComponent, FilterDateEditorComponent, FilterExpressionComponent, FilterExpressionOperatorsComponent, FilterGroupComponent, FilterModule, FilterNumericEditorComponent, FilterTextEditorComponent, LocalizedMessagesDirective };
1762
+ export { AriaLabelValueDirective, CustomMessagesComponent, FilterBooleanEditorComponent, FilterComponent, FilterDateEditorComponent, FilterExpressionComponent, FilterExpressionOperatorsComponent, FilterFieldComponent, FilterGroupComponent, FilterModule, FilterNumericEditorComponent, FilterTextEditorComponent, FilterValueEditorTemplateDirective, LocalizedMessagesDirective };
1650
1763