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

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";
@@ -55,6 +56,7 @@ export class FilterComponent {
55
56
  * That is each time a Filter Group or Filter Expression is added, removed, or updated.
56
57
  */
57
58
  this.valueChange = new EventEmitter();
59
+ this._value = { filters: [], logic: 'and' };
58
60
  validatePackage(packageMetadata);
59
61
  this.direction = localization.rtl ? 'rtl' : 'ltr';
60
62
  }
@@ -62,16 +64,16 @@ export class FilterComponent {
62
64
  * Specifies the available user-defined filters. At least one filter should be provided.
63
65
  */
64
66
  set filters(_filters) {
65
- if (isDevMode() && (!isArray(_filters) || _filters.length === 0)) {
66
- 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);
67
76
  }
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
77
  }
76
78
  get filters() {
77
79
  return this.filterService.filters;
@@ -81,21 +83,28 @@ export class FilterComponent {
81
83
  */
82
84
  set value(value) {
83
85
  const clonedValue = JSON.parse(JSON.stringify(value));
84
- this.normalizeValue(clonedValue);
85
- this.filterService.value = clonedValue;
86
+ this._value = clonedValue;
87
+ if (this.filters.length > 0) {
88
+ this.setValue(this.value);
89
+ }
86
90
  }
87
91
  get value() {
88
- return this.filterService.value;
92
+ return this._value;
89
93
  }
90
94
  ngOnInit() {
91
- if (this.filters.length === 0) {
92
- 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`);
93
- }
94
95
  this.localizationSubscription = this.localization.changes.subscribe(({ rtl }) => {
95
96
  this.direction = rtl ? 'rtl' : 'ltr';
96
97
  this.cdr.detectChanges();
97
98
  });
98
99
  }
100
+ ngAfterViewChecked() {
101
+ if (this.filterFields && this.filterFields.length > 0) {
102
+ this.filters = this.filterFields.map((filterField) => filterField);
103
+ }
104
+ if (this.filters.length === 0) {
105
+ 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`);
106
+ }
107
+ }
99
108
  ngOnDestroy() {
100
109
  if (this.localizationSubscription) {
101
110
  this.localizationSubscription.unsubscribe();
@@ -105,13 +114,13 @@ export class FilterComponent {
105
114
  * @hidden
106
115
  */
107
116
  getCurrentFilter() {
108
- return this.value;
117
+ return this.filterService.normalizedValue;
109
118
  }
110
119
  /**
111
120
  * @hidden
112
121
  */
113
122
  onValueChange() {
114
- this.valueChange.emit(this.filterService.value);
123
+ this.valueChange.emit(this.filterService.normalizedValue);
115
124
  }
116
125
  normalizeFilter(filterDescriptor) {
117
126
  const foundFilter = this.filterService.filters.find((filter) => filter.field === filterDescriptor.field);
@@ -137,8 +146,15 @@ export class FilterComponent {
137
146
  filterDescriptor.value = null;
138
147
  }
139
148
  }
140
- normalizeValue(item) {
141
- item.filters.forEach((item) => {
149
+ setValue(items) {
150
+ this.normalizeValue(items);
151
+ this.filterService.normalizedValue = items;
152
+ }
153
+ normalizeValue(items) {
154
+ if (!this.filterService.filters.length) {
155
+ return;
156
+ }
157
+ items.filters.forEach((item) => {
142
158
  if (item.filters) {
143
159
  this.normalizeValue(item);
144
160
  }
@@ -156,7 +172,7 @@ FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
156
172
  useValue: 'kendo.filter'
157
173
  },
158
174
  FilterService
159
- ], ngImport: i0, template: `
175
+ ], queries: [{ propertyName: "filterFields", predicate: FilterFieldComponent }], ngImport: i0, template: `
160
176
  <ng-container kendoFilterLocalizedMessages
161
177
  i18n-editorDateTodayText="kendo.filter.editorDateTodayText|The text of the Today button of the Date editor"
162
178
  editorDateTodayText="Today"
@@ -281,7 +297,7 @@ FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
281
297
  </li>
282
298
  </ul>
283
299
  </div>
284
- `, isInline: true, components: [{ type: i3.FilterGroupComponent, selector: "kendo-filter-group", inputs: ["index", "currentItem"], outputs: ["valueChange"] }], directives: [{ type: i4.LocalizedMessagesDirective, selector: "[kendoFilterLocalizedMessages]" }] });
300
+ `, isInline: true, components: [{ type: i3.FilterGroupComponent, selector: "kendo-filter-group", inputs: ["index", "currentItem"], outputs: ["valueChange"] }], directives: [{ type: i4.LocalizedMessagesDirective, selector: "[kendoFilterLocalizedMessages]" }] });
285
301
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterComponent, decorators: [{
286
302
  type: Component,
287
303
  args: [{
@@ -419,7 +435,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
419
435
  </li>
420
436
  </ul>
421
437
  </div>
422
- `
438
+ `
423
439
  }]
424
440
  }], ctorParameters: function () { return [{ type: i1.FilterService }, { type: i2.LocalizationService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { direction: [{
425
441
  type: HostBinding,
@@ -430,4 +446,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
430
446
  type: Input
431
447
  }], valueChange: [{
432
448
  type: Output
449
+ }], filterFields: [{
450
+ type: ContentChildren,
451
+ args: [FilterFieldComponent]
433
452
  }] } });
@@ -10,6 +10,7 @@ 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';
@@ -60,7 +61,8 @@ FilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "
60
61
  FilterDateEditorComponent,
61
62
  LocalizedMessagesDirective,
62
63
  CustomMessagesComponent,
63
- AriaLabelValueDirective], imports: [SharedModule], exports: [FilterComponent,
64
+ AriaLabelValueDirective,
65
+ FilterFieldComponent], imports: [SharedModule], exports: [FilterComponent,
64
66
  FilterNumericEditorComponent,
65
67
  FilterTextEditorComponent,
66
68
  FilterExpressionComponent,
@@ -70,7 +72,8 @@ FilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "
70
72
  FilterDateEditorComponent,
71
73
  LocalizedMessagesDirective,
72
74
  CustomMessagesComponent,
73
- AriaLabelValueDirective] });
75
+ AriaLabelValueDirective,
76
+ FilterFieldComponent] });
74
77
  FilterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterModule, imports: [[SharedModule]] });
75
78
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterModule, decorators: [{
76
79
  type: NgModule,
@@ -86,7 +89,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
86
89
  FilterDateEditorComponent,
87
90
  LocalizedMessagesDirective,
88
91
  CustomMessagesComponent,
89
- AriaLabelValueDirective
92
+ AriaLabelValueDirective,
93
+ FilterFieldComponent
90
94
  ],
91
95
  exports: [FilterComponent,
92
96
  FilterNumericEditorComponent,
@@ -98,6 +102,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
98
102
  FilterDateEditorComponent,
99
103
  LocalizedMessagesDirective,
100
104
  CustomMessagesComponent,
101
- AriaLabelValueDirective]
105
+ AriaLabelValueDirective,
106
+ FilterFieldComponent]
102
107
  }]
103
108
  }] });
@@ -9,11 +9,11 @@ import * as i0 from "@angular/core";
9
9
  */
10
10
  export class FilterService {
11
11
  constructor() {
12
- this.value = { filters: [], logic: 'or' };
12
+ this.normalizedValue = { logic: 'and', filters: [] };
13
13
  this.filters = [];
14
14
  }
15
15
  addFilterGroup(item) {
16
- let filterGroup = { logic: 'or', filters: [] };
16
+ let filterGroup = { logic: 'and', filters: [] };
17
17
  item.filters.push(filterGroup);
18
18
  }
19
19
  addFilterExpression(item) {
@@ -22,7 +22,7 @@ export class FilterService {
22
22
  }
23
23
  remove(item, positionIndex, parentItem) {
24
24
  if (!parentItem) {
25
- parentItem = this.value;
25
+ parentItem = this.normalizedValue;
26
26
  }
27
27
  if (item === parentItem) {
28
28
  parentItem.filters = [];
package/esm2015/main.js CHANGED
@@ -14,3 +14,4 @@ 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';
@@ -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: 1652799999,
12
+ publishDate: 1654698725,
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
  };
@@ -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, Component, Input, Directive, 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,11 +24,11 @@ import { LabelModule } from '@progress/kendo-angular-label';
24
24
  */
25
25
  class FilterService {
26
26
  constructor() {
27
- this.value = { filters: [], logic: 'or' };
27
+ this.normalizedValue = { logic: 'and', filters: [] };
28
28
  this.filters = [];
29
29
  }
30
30
  addFilterGroup(item) {
31
- let filterGroup = { logic: 'or', filters: [] };
31
+ let filterGroup = { logic: 'and', filters: [] };
32
32
  item.filters.push(filterGroup);
33
33
  }
34
34
  addFilterExpression(item) {
@@ -37,7 +37,7 @@ class FilterService {
37
37
  }
38
38
  remove(item, positionIndex, parentItem) {
39
39
  if (!parentItem) {
40
- parentItem = this.value;
40
+ parentItem = this.normalizedValue;
41
41
  }
42
42
  if (item === parentItem) {
43
43
  parentItem.filters = [];
@@ -201,11 +201,69 @@ const packageMetadata = {
201
201
  name: '@progress/kendo-angular-filter',
202
202
  productName: 'Kendo UI for Angular',
203
203
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
204
- publishDate: 1652799999,
204
+ publishDate: 1654698725,
205
205
  version: '',
206
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'
207
207
  };
208
208
 
209
+ /**
210
+ * Represents the [Kendo UI Filter Field component for Angular]({% slug api_filter_filterfieldcomponent %}).
211
+ * The Filter Field component can be used to add Filter Expressions declaratively.
212
+ * @example
213
+ * ```
214
+ * @Component({
215
+ * selector: 'my-app',
216
+ * template: `
217
+ * <kendo-filter (valueChange)="onValueChange($event)">
218
+ * <kendo-filter-field field="country" editor="string" [operators]="['neq', 'eq', 'contains']"></kendo-filter-field>
219
+ * <kendo-filter-field field="budget" editor="number"></kendo-filter-field>
220
+ * <kendo-filter-field field="discontinued" title="Discontinued" editor="boolean"></kendo-filter-field>
221
+ * <kendo-filter-field field="ordered on" title="Ordered on" editor="date"></kendo-filter-field>
222
+ * <kendo-filter>
223
+ * `
224
+ * })
225
+ * export class AppComponent {
226
+ * onValueChange(e: CompositeFilterDescriptor){
227
+ * console.log(e)
228
+ * }
229
+ * }
230
+ * ```
231
+ */
232
+ class FilterFieldComponent {
233
+ /**
234
+ * Specifies the `title` text that will be displayed by the user-defined filter.
235
+ * If the `title` isn't set, the value passed to `field` is used.
236
+ */
237
+ set title(_title) {
238
+ if (_title) {
239
+ this._title = _title;
240
+ }
241
+ else {
242
+ this._title = this.field;
243
+ }
244
+ }
245
+ get title() {
246
+ return this._title;
247
+ }
248
+ }
249
+ FilterFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
250
+ 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" }, ngImport: i0, template: ``, isInline: true });
251
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterFieldComponent, decorators: [{
252
+ type: Component,
253
+ args: [{
254
+ selector: 'kendo-filter-field',
255
+ template: ``
256
+ }]
257
+ }], propDecorators: { field: [{
258
+ type: Input
259
+ }], title: [{
260
+ type: Input
261
+ }], editor: [{
262
+ type: Input
263
+ }], operators: [{
264
+ type: Input
265
+ }] } });
266
+
209
267
  /**
210
268
  * @hidden
211
269
  */
@@ -235,18 +293,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
235
293
  class FilterExpressionOperatorsComponent {
236
294
  constructor(localization) {
237
295
  this.localization = localization;
238
- this.operators = [];
239
296
  this.valueChange = new EventEmitter();
297
+ this.operators = [];
240
298
  }
241
299
  messageFor(key) {
242
300
  return this.localization.get(key);
243
301
  }
302
+ getOperator(operatorValue) {
303
+ return this.messageFor(getKeyByValue(defaultOperators[this.editorType], operatorValue));
304
+ }
244
305
  operatorValueChange(value) {
245
306
  this.valueChange.emit(value);
246
307
  }
247
308
  }
248
309
  FilterExpressionOperatorsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionOperatorsComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
249
- FilterExpressionOperatorsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterExpressionOperatorsComponent, selector: "kendo-filter-expression-operators", inputs: { currentItem: "currentItem", operators: "operators" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
310
+ FilterExpressionOperatorsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterExpressionOperatorsComponent, selector: "kendo-filter-expression-operators", inputs: { currentItem: "currentItem", editorType: "editorType", operators: "operators" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
250
311
  <kendo-dropdownlist
251
312
  [kendoAriaLabelValue]="messageFor('filterOperatorAriaLabel')"
252
313
  [data]="operators"
@@ -257,8 +318,14 @@ FilterExpressionOperatorsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersio
257
318
  textField="text"
258
319
  valueField="value"
259
320
  >
321
+ <ng-template kendoDropDownListValueTemplate let-dataItem>
322
+ {{ getOperator(dataItem.value) }}
323
+ </ng-template>
324
+ <ng-template kendoDropDownListItemTemplate let-dataItem>
325
+ {{ getOperator(dataItem.value) }}
326
+ </ng-template>
260
327
  </kendo-dropdownlist>
261
- `, 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"] }], directives: [{ type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }] });
328
+ `, 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"] }], directives: [{ type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }, { type: i2.ValueTemplateDirective, selector: "[kendoDropDownListValueTemplate],[kendoDropDownTreeValueTemplate]" }, { type: i2.ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }] });
262
329
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionOperatorsComponent, decorators: [{
263
330
  type: Component,
264
331
  args: [{
@@ -274,15 +341,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
274
341
  textField="text"
275
342
  valueField="value"
276
343
  >
344
+ <ng-template kendoDropDownListValueTemplate let-dataItem>
345
+ {{ getOperator(dataItem.value) }}
346
+ </ng-template>
347
+ <ng-template kendoDropDownListItemTemplate let-dataItem>
348
+ {{ getOperator(dataItem.value) }}
349
+ </ng-template>
277
350
  </kendo-dropdownlist>
278
351
  `
279
352
  }]
280
353
  }], ctorParameters: function () { return [{ type: i1.LocalizationService }]; }, propDecorators: { currentItem: [{
281
354
  type: Input
282
- }], operators: [{
355
+ }], editorType: [{
283
356
  type: Input
284
357
  }], valueChange: [{
285
358
  type: Output
359
+ }], operators: [{
360
+ type: Input
286
361
  }] } });
287
362
 
288
363
  /**
@@ -644,6 +719,7 @@ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.
644
719
  <kendo-filter-expression-operators
645
720
  [currentItem]="currentItem"
646
721
  [operators]="operators"
722
+ [editorType]="getEditorType()"
647
723
  (valueChange)="onOperatorChange($event);">
648
724
  </kendo-filter-expression-operators>
649
725
  </div>
@@ -666,7 +742,7 @@ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.
666
742
  </div>
667
743
  </div>
668
744
  </div>
669
- `, 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", "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"] }] });
745
+ `, 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"] }] });
670
746
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionComponent, decorators: [{
671
747
  type: Component,
672
748
  args: [{
@@ -690,6 +766,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
690
766
  <kendo-filter-expression-operators
691
767
  [currentItem]="currentItem"
692
768
  [operators]="operators"
769
+ [editorType]="getEditorType()"
693
770
  (valueChange)="onOperatorChange($event);">
694
771
  </kendo-filter-expression-operators>
695
772
  </div>
@@ -756,6 +833,9 @@ class FilterGroupComponent {
756
833
  messageFor(key) {
757
834
  return this.localization.get(key);
758
835
  }
836
+ getOperator(operatorValue) {
837
+ return this.messageFor(getKeyByValue(logicOperators, operatorValue));
838
+ }
759
839
  selectedChange(logicOperator) {
760
840
  if (this.currentItem.logic !== logicOperator) {
761
841
  this.currentItem.logic = logicOperator;
@@ -789,7 +869,7 @@ FilterGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", v
789
869
  [title]="operator.text"
790
870
  (click)="selectedChange(operator.value)"
791
871
  >
792
- {{operator.text}}
872
+ {{getOperator(operator.value)}}
793
873
  </button>
794
874
  </div>
795
875
  </div>
@@ -857,7 +937,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
857
937
  [title]="operator.text"
858
938
  (click)="selectedChange(operator.value)"
859
939
  >
860
- {{operator.text}}
940
+ {{getOperator(operator.value)}}
861
941
  </button>
862
942
  </div>
863
943
  </div>
@@ -1076,6 +1156,7 @@ class FilterComponent {
1076
1156
  * That is each time a Filter Group or Filter Expression is added, removed, or updated.
1077
1157
  */
1078
1158
  this.valueChange = new EventEmitter();
1159
+ this._value = { filters: [], logic: 'and' };
1079
1160
  validatePackage(packageMetadata);
1080
1161
  this.direction = localization.rtl ? 'rtl' : 'ltr';
1081
1162
  }
@@ -1083,16 +1164,16 @@ class FilterComponent {
1083
1164
  * Specifies the available user-defined filters. At least one filter should be provided.
1084
1165
  */
1085
1166
  set filters(_filters) {
1086
- if (isDevMode() && (!isArray(_filters) || _filters.length === 0)) {
1087
- 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`);
1167
+ if (_filters.length > 0) {
1168
+ this.filterService.filters = _filters.map(filterExpression => {
1169
+ let clonedFilter = Object.assign({}, filterExpression);
1170
+ if (!clonedFilter.title) {
1171
+ clonedFilter.title = clonedFilter.field;
1172
+ }
1173
+ return clonedFilter;
1174
+ });
1175
+ this.setValue(this.value);
1088
1176
  }
1089
- this.filterService.filters = _filters.map(filterExpression => {
1090
- let clonedFilter = Object.assign({}, filterExpression);
1091
- if (!clonedFilter.title) {
1092
- clonedFilter.title = clonedFilter.field;
1093
- }
1094
- return clonedFilter;
1095
- });
1096
1177
  }
1097
1178
  get filters() {
1098
1179
  return this.filterService.filters;
@@ -1102,21 +1183,28 @@ class FilterComponent {
1102
1183
  */
1103
1184
  set value(value) {
1104
1185
  const clonedValue = JSON.parse(JSON.stringify(value));
1105
- this.normalizeValue(clonedValue);
1106
- this.filterService.value = clonedValue;
1186
+ this._value = clonedValue;
1187
+ if (this.filters.length > 0) {
1188
+ this.setValue(this.value);
1189
+ }
1107
1190
  }
1108
1191
  get value() {
1109
- return this.filterService.value;
1192
+ return this._value;
1110
1193
  }
1111
1194
  ngOnInit() {
1112
- if (this.filters.length === 0) {
1113
- 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`);
1114
- }
1115
1195
  this.localizationSubscription = this.localization.changes.subscribe(({ rtl }) => {
1116
1196
  this.direction = rtl ? 'rtl' : 'ltr';
1117
1197
  this.cdr.detectChanges();
1118
1198
  });
1119
1199
  }
1200
+ ngAfterViewChecked() {
1201
+ if (this.filterFields && this.filterFields.length > 0) {
1202
+ this.filters = this.filterFields.map((filterField) => filterField);
1203
+ }
1204
+ if (this.filters.length === 0) {
1205
+ 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`);
1206
+ }
1207
+ }
1120
1208
  ngOnDestroy() {
1121
1209
  if (this.localizationSubscription) {
1122
1210
  this.localizationSubscription.unsubscribe();
@@ -1126,13 +1214,13 @@ class FilterComponent {
1126
1214
  * @hidden
1127
1215
  */
1128
1216
  getCurrentFilter() {
1129
- return this.value;
1217
+ return this.filterService.normalizedValue;
1130
1218
  }
1131
1219
  /**
1132
1220
  * @hidden
1133
1221
  */
1134
1222
  onValueChange() {
1135
- this.valueChange.emit(this.filterService.value);
1223
+ this.valueChange.emit(this.filterService.normalizedValue);
1136
1224
  }
1137
1225
  normalizeFilter(filterDescriptor) {
1138
1226
  const foundFilter = this.filterService.filters.find((filter) => filter.field === filterDescriptor.field);
@@ -1158,8 +1246,15 @@ class FilterComponent {
1158
1246
  filterDescriptor.value = null;
1159
1247
  }
1160
1248
  }
1161
- normalizeValue(item) {
1162
- item.filters.forEach((item) => {
1249
+ setValue(items) {
1250
+ this.normalizeValue(items);
1251
+ this.filterService.normalizedValue = items;
1252
+ }
1253
+ normalizeValue(items) {
1254
+ if (!this.filterService.filters.length) {
1255
+ return;
1256
+ }
1257
+ items.filters.forEach((item) => {
1163
1258
  if (item.filters) {
1164
1259
  this.normalizeValue(item);
1165
1260
  }
@@ -1177,7 +1272,7 @@ FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
1177
1272
  useValue: 'kendo.filter'
1178
1273
  },
1179
1274
  FilterService
1180
- ], ngImport: i0, template: `
1275
+ ], queries: [{ propertyName: "filterFields", predicate: FilterFieldComponent }], ngImport: i0, template: `
1181
1276
  <ng-container kendoFilterLocalizedMessages
1182
1277
  i18n-editorDateTodayText="kendo.filter.editorDateTodayText|The text of the Today button of the Date editor"
1183
1278
  editorDateTodayText="Today"
@@ -1302,7 +1397,7 @@ FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
1302
1397
  </li>
1303
1398
  </ul>
1304
1399
  </div>
1305
- `, isInline: true, components: [{ type: FilterGroupComponent, selector: "kendo-filter-group", inputs: ["index", "currentItem"], outputs: ["valueChange"] }], directives: [{ type: LocalizedMessagesDirective, selector: "[kendoFilterLocalizedMessages]" }] });
1400
+ `, isInline: true, components: [{ type: FilterGroupComponent, selector: "kendo-filter-group", inputs: ["index", "currentItem"], outputs: ["valueChange"] }], directives: [{ type: LocalizedMessagesDirective, selector: "[kendoFilterLocalizedMessages]" }] });
1306
1401
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterComponent, decorators: [{
1307
1402
  type: Component,
1308
1403
  args: [{
@@ -1440,7 +1535,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1440
1535
  </li>
1441
1536
  </ul>
1442
1537
  </div>
1443
- `
1538
+ `
1444
1539
  }]
1445
1540
  }], ctorParameters: function () { return [{ type: FilterService }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { direction: [{
1446
1541
  type: HostBinding,
@@ -1451,6 +1546,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1451
1546
  type: Input
1452
1547
  }], valueChange: [{
1453
1548
  type: Output
1549
+ }], filterFields: [{
1550
+ type: ContentChildren,
1551
+ args: [FilterFieldComponent]
1454
1552
  }] } });
1455
1553
 
1456
1554
  /**
@@ -1570,7 +1668,8 @@ FilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "
1570
1668
  FilterDateEditorComponent,
1571
1669
  LocalizedMessagesDirective,
1572
1670
  CustomMessagesComponent,
1573
- AriaLabelValueDirective], imports: [SharedModule], exports: [FilterComponent,
1671
+ AriaLabelValueDirective,
1672
+ FilterFieldComponent], imports: [SharedModule], exports: [FilterComponent,
1574
1673
  FilterNumericEditorComponent,
1575
1674
  FilterTextEditorComponent,
1576
1675
  FilterExpressionComponent,
@@ -1580,7 +1679,8 @@ FilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "
1580
1679
  FilterDateEditorComponent,
1581
1680
  LocalizedMessagesDirective,
1582
1681
  CustomMessagesComponent,
1583
- AriaLabelValueDirective] });
1682
+ AriaLabelValueDirective,
1683
+ FilterFieldComponent] });
1584
1684
  FilterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterModule, imports: [[SharedModule]] });
1585
1685
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterModule, decorators: [{
1586
1686
  type: NgModule,
@@ -1596,7 +1696,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1596
1696
  FilterDateEditorComponent,
1597
1697
  LocalizedMessagesDirective,
1598
1698
  CustomMessagesComponent,
1599
- AriaLabelValueDirective
1699
+ AriaLabelValueDirective,
1700
+ FilterFieldComponent
1600
1701
  ],
1601
1702
  exports: [FilterComponent,
1602
1703
  FilterNumericEditorComponent,
@@ -1608,7 +1709,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1608
1709
  FilterDateEditorComponent,
1609
1710
  LocalizedMessagesDirective,
1610
1711
  CustomMessagesComponent,
1611
- AriaLabelValueDirective]
1712
+ AriaLabelValueDirective,
1713
+ FilterFieldComponent]
1612
1714
  }]
1613
1715
  }] });
1614
1716
 
@@ -1616,5 +1718,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1616
1718
  * Generated bundle index. Do not edit.
1617
1719
  */
1618
1720
 
1619
- export { AriaLabelValueDirective, CustomMessagesComponent, FilterBooleanEditorComponent, FilterComponent, FilterDateEditorComponent, FilterExpressionComponent, FilterExpressionOperatorsComponent, FilterGroupComponent, FilterModule, FilterNumericEditorComponent, FilterTextEditorComponent, LocalizedMessagesDirective };
1721
+ export { AriaLabelValueDirective, CustomMessagesComponent, FilterBooleanEditorComponent, FilterComponent, FilterDateEditorComponent, FilterExpressionComponent, FilterExpressionOperatorsComponent, FilterFieldComponent, FilterGroupComponent, FilterModule, FilterNumericEditorComponent, FilterTextEditorComponent, LocalizedMessagesDirective };
1620
1722