@syncfusion/ej2-multicolumn-combobox 31.1.17 → 31.2.2

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.
@@ -1,2521 +0,0 @@
1
- import { Component, EventHandler, INotifyPropertyChanged, Property, NotifyPropertyChanges, closest, attributes, append, compile, detach, KeyboardEvents, getValue } from '@syncfusion/ej2-base';
2
- import { ChildProperty, prepend, Collection, getUniqueID, Complex, isNullOrUndefined as isNOU, select, L10n, Browser } from '@syncfusion/ej2-base';
3
- import { formatUnit, addClass, removeClass, NumberFormatOptions, DateFormatOptions, Event, EmitType, AnimationModel, Animation, KeyboardEventArgs } from '@syncfusion/ej2-base';
4
- import { Input, InputObject } from '@syncfusion/ej2-inputs';
5
- import { DataManager, Query, Group, DataOptions } from '@syncfusion/ej2-data';
6
- import { Popup, createSpinner, showSpinner, hideSpinner } from '@syncfusion/ej2-popups';
7
- import { Grid, Resize, FailureEventArgs, VirtualScroll, Group as GridGroup, Edit, Sort, GridColumnModel } from '@syncfusion/ej2-grids';
8
-
9
- import { MultiColumnComboBoxModel } from './multi-column-combo-box-model';
10
- import { ColumnModel, FieldSettingsModel, GridSettingsModel } from './multi-column-combo-box-model';
11
-
12
- const DROPDOWNICON: string = 'e-input-group-icon e-multicolumn-list-icon e-icons';
13
- const CONTENT: string = 'e-popup-content';
14
- const ICONANIMATION: string = 'e-icon-anim';
15
- const NODATA: string = 'e-nodata';
16
- const DISABLED: string = 'e-disabled';
17
- const INPUTFOCUS: string = 'e-input-focus';
18
- const MULTICOLUMNLIST: string = 'e-multicolumn-list';
19
- const HIDDENELEMENT: string = 'e-multicolumn-list-hidden';
20
- const MULTICOLUMNGRID: string = 'e-multicolumn-grid';
21
-
22
- export class MultiColumnGrid {
23
- /**
24
- * Injecting required modules for component.
25
- *
26
- * @returns {void}
27
- * @private
28
- */
29
- public InjectModules(): void {
30
- Grid.Inject(VirtualScroll, GridGroup, Edit, Sort, Resize);
31
- }
32
- }
33
-
34
- /**
35
- * Defines alignments of text, they are
36
- * ```props
37
- * * Left :- Defines Left alignment
38
- * * Right :- Defines Right alignment
39
- * * Center :- Defines Center alignment
40
- * * Justify :- Defines Justify alignment
41
- * ```
42
- */
43
- export type TextAlign = 'Left' | 'Right' | 'Center' | 'Justify';
44
-
45
- /**
46
- * Defines modes of GridLine, They are
47
- * ```props
48
- * * Both :- Displays both the horizontal and vertical grid lines.
49
- * * None :- No grid lines are displayed.
50
- * * Horizontal :- Displays the horizontal grid lines only.
51
- * * Vertical :- Displays the vertical grid lines only.
52
- * * Default :- Displays grid lines based on the theme.
53
- * ```
54
- */
55
- export type GridLine = 'Both' | 'None' | 'Horizontal' | 'Vertical' | 'Default';
56
-
57
- /**
58
- * Defines floating label type of the input and decides how the label should float on the input.
59
- */
60
- export type FloatLabelType = 'Never' | 'Always' | 'Auto';
61
-
62
- /**
63
- * Defines the filter type.
64
- */
65
- export enum FilterType {
66
- /**
67
- * Checks whether a value begins with the specified value.
68
- */
69
- StartsWith = 'StartsWith',
70
- /**
71
- * Checks whether a value ends with specified value.
72
- */
73
- EndsWith = 'EndsWith',
74
- /**
75
- * Checks whether a value contains with specified value.
76
- */
77
- Contains = 'Contains'
78
- }
79
-
80
- /**
81
- * Specifies the sortOrder to sort the data source.
82
- */
83
- export enum SortOrder {
84
- /**
85
- * The datasource is not sorting. Default value is None.
86
- */
87
- None = 'None',
88
-
89
- /**
90
- * The datasource is sorting with ascending order.
91
- */
92
- Ascending = 'Ascending',
93
-
94
- /**
95
- * The data source is sorting with descending order.
96
- */
97
- Descending = 'Descending'
98
- }
99
-
100
- /**
101
- * Specifies the type of sorting to be applied for the columns.
102
- */
103
- export enum SortType {
104
- /**
105
- * Allow sorting only one column
106
- */
107
- OneColumn = 'OneColumn',
108
- /**
109
- * Allow sorting multiple columns
110
- */
111
- MultipleColumns = 'MultipleColumns'
112
-
113
- }
114
-
115
- /**
116
- * Specifies the type of wrap mode to be applied for the grid cells.
117
- */
118
- export enum WrapMode {
119
- /**
120
- * Specifies that both header and content text wrapping are enabled.
121
- */
122
- Both = 'Both',
123
- /**
124
- * Specifies that only content text wrapping is enabled.
125
- */
126
- Content = 'Content',
127
- /**
128
- * Specifies that only header text wrapping is enabled.
129
- */
130
- Header = 'Header'
131
- }
132
-
133
- /**
134
- * The fields property maps the columns of the data table and binds the data to the component.
135
- */
136
- export class FieldSettings extends ChildProperty<FieldSettings> {
137
- /**
138
- * Specifies the display text of each list item.
139
- *
140
- * @default null
141
- */
142
- @Property()
143
- public text: string;
144
-
145
- /**
146
- * Specifies the hidden data value mapped to each list item that should contain a unique value.
147
- *
148
- * @default null
149
- */
150
- @Property()
151
- public value: string;
152
-
153
- /**
154
- * Specifies the category under which the list item has to be grouped.
155
- *
156
- * @default null
157
- */
158
- @Property()
159
- public groupBy: string;
160
- }
161
-
162
- /**
163
- * Specifies the number of columns and its respective fields to be displayed in the dropdown popup.
164
- */
165
- export class Column extends ChildProperty<Column> {
166
-
167
- /**
168
- * Defines the name of the field whose data will be displayed in the column.
169
- *
170
- * @default ''
171
- */
172
- @Property('')
173
- public field: string;
174
-
175
- /**
176
- * Defines the header text of column which is used to display in column header.
177
- * If headerText is not defined, then field name value will be assigned to header text.
178
- *
179
- * @default ''
180
- */
181
- @Property('')
182
- public header: string;
183
-
184
- /**
185
- * Defines the width of the column in pixels or percentage.
186
- *
187
- * @default ''
188
- */
189
- @Property('')
190
- public width: string | number;
191
-
192
- /**
193
- * Defines the alignment of the column in both header and content cells.
194
- *
195
- * @default Left
196
- */
197
- @Property('')
198
- public textAlign: TextAlign;
199
-
200
- /**
201
- * It is used to change display value with the given format and does not affect the original data.
202
- * Gets the format from the user which can be standard or custom `number` and `date` formats.
203
- *
204
- * @default null
205
- * @aspType string
206
- */
207
- @Property(null)
208
- public format: string | NumberFormatOptions | DateFormatOptions;
209
-
210
- /**
211
- * If `displayAsCheckBox` is set to true, it displays the column value as a check box instead of Boolean value.
212
- *
213
- * @default false
214
- */
215
- @Property(false)
216
- public displayAsCheckBox: boolean;
217
-
218
- /**
219
- * Defines the column template that renders customized element in each cell of the column.
220
- * It accepts either template or HTML element ID.
221
- *
222
- * @default null
223
- * @angularType string | object
224
- * @reactType string | function | JSX.Element
225
- * @vueType string | function
226
- * @aspType string
227
- */
228
- @Property(null)
229
- public template: string | Function;
230
-
231
- /**
232
- * Defines the column template as string or HTML element ID which is used to add customized element in the column header.
233
- *
234
- * @default null
235
- * @angularType string | object
236
- * @reactType string | function | JSX.Element
237
- * @vueType string | function
238
- * @aspType string
239
- */
240
- @Property(null)
241
- public headerTemplate: string | Function;
242
-
243
- /**
244
- * The CSS styles and attributes of the content cells of a particular column can be customized.
245
- *
246
- * @default null
247
- */
248
- @Property(null)
249
- public customAttributes: { [x: string]: Object };
250
- }
251
-
252
- /**
253
- * Specifies the configuration of the columns in the popup content.
254
- */
255
- export class GridSettings extends ChildProperty<GridSettings> {
256
- /**
257
- * If `enableAltRow` is set to true, the grid will render with `e-altrow` CSS class to the alternative row elements.
258
- *
259
- * @default false
260
- */
261
- @Property(false)
262
- public enableAltRow: boolean;
263
-
264
- /**
265
- * Defines the height of rows in the popup content.
266
- *
267
- * @default null
268
- */
269
- @Property(null)
270
- public rowHeight: number;
271
-
272
- /**
273
- * Defines the mode of grid lines. The available modes are,
274
- * * `Both`: Displays both horizontal and vertical grid lines.
275
- * * `None`: No grid lines are displayed.
276
- * * `Horizontal`: Displays the horizontal grid lines only.
277
- * * `Vertical`: Displays the vertical grid lines only.
278
- * * `Default`: Displays grid lines based on the theme.
279
- *
280
- * @default Default
281
- */
282
- @Property('Default')
283
- public gridLines: GridLine;
284
-
285
- /**
286
- * Specifies whether to allow text wrapping of the popup grid content.
287
- *
288
- * @default false
289
- */
290
- @Property(false)
291
- public allowTextWrap: boolean;
292
-
293
- /**
294
- * Specifies the mode for text wrapping in the popup grid content. Options include 'Both', 'Content', and 'Header'.
295
- *
296
- * @isenumeration true
297
- *
298
- * @default WrapMode.Both
299
- * @asptype WrapMode
300
- */
301
- @Property(WrapMode.Both)
302
- public textWrapMode: WrapMode | string;
303
-
304
- /**
305
- * Specifies whether resizing of columns is enabled in the popup grid content.
306
- *
307
- * @default false
308
- */
309
- @Property(false)
310
- public allowResizing: boolean;
311
-
312
- /**
313
- * Triggers during the column resizing.
314
- *
315
- * @event resizing
316
- */
317
- @Event()
318
- public resizing: EmitType<ResizeArgs>;
319
-
320
- /**
321
- * Triggers when the column resizing begins.
322
- *
323
- * @event resizeStart
324
- */
325
- @Event()
326
- public resizeStart: EmitType<ResizeArgs>;
327
-
328
- /**
329
- * Triggers when the column resizing ends.
330
- *
331
- * @event resizeStop
332
- */
333
- @Event()
334
- public resizeStop: EmitType<ResizeArgs>;
335
- }
336
-
337
- export interface PopupEventArgs {
338
- /**
339
- * Specifies the popup Object.
340
- *
341
- * @deprecated
342
- */
343
- popup: Popup
344
- /**
345
- * Illustrates whether the current action needs to be prevented or not.
346
- */
347
- cancel?: boolean
348
- /**
349
- * Specifies the animation for the popup.
350
- */
351
- animation?: AnimationModel
352
- /**
353
- * Specifies the original event arguments
354
- */
355
- event?: MouseEvent | KeyboardEvent | TouchEvent
356
- }
357
-
358
- export interface FilteringEventArgs {
359
- /**
360
- * To prevent the internal filtering action.
361
- */
362
- preventDefaultAction: boolean
363
- /**
364
- * Gets the `keyup` event arguments.
365
- */
366
- event: Object
367
- /**
368
- * Illustrates whether the current action needs to be prevented or not.
369
- */
370
- cancel: boolean
371
- /**
372
- * Returns the searched text value.
373
- */
374
- text: string
375
- /**
376
- * Opens the popup that displays the list of items.
377
- *
378
- * @param {Object[] | DataManager | DataResult } dataSource - Set the data source to filter.
379
- * @param {Query} query - Specify the query to filter the data.
380
- * @param {FieldSettingsModel} fields - Specify the fields to map the column in the data table.
381
- * @returns {void}
382
- */
383
- updateData(dataSource: { [key: string]: Object }[] | DataManager | DataResult, query?: Query,
384
- fields?: FieldSettingsModel): void
385
- }
386
-
387
- export interface SelectEventArgs {
388
- /**
389
- * Returns true if the event is triggered by interaction. Otherwise, it returns false.
390
- */
391
- isInteracted: boolean
392
- /**
393
- * Returns the selected row data.
394
- */
395
- item: Object
396
- /**
397
- * Returns the selected item as JSON Object from the data source.
398
- *
399
- */
400
- itemData: { text: string, value: string }
401
- /**
402
- * Returns the selected row item.
403
- *
404
- */
405
- itemElement: HTMLElement
406
- /**
407
- * Specifies the original event arguments.
408
- */
409
- event: MouseEvent | KeyboardEvent | TouchEvent
410
- /**
411
- * Specifies whether the current action needs to be prevented or not.
412
- */
413
- cancel?: boolean
414
- }
415
-
416
- export interface ChangeEventArgs {
417
- /**
418
- * Specifies the original event arguments.
419
- */
420
- event: MouseEvent | KeyboardEvent | TouchEvent
421
- /**
422
- * Specifies whether the current action needs to be prevented or not.
423
- */
424
- cancel?: boolean
425
- /**
426
- * Returns true if the event is triggered by interaction. Otherwise, it returns false.
427
- */
428
- isInteracted: boolean
429
- /**
430
- * Returns the selected tr element.
431
- */
432
- itemElement: HTMLElement
433
- /**
434
- * Returns the selected item as JSON Object from the data source.
435
- */
436
- itemData: { text: string, value: string }
437
- /**
438
- * Returns the previous selected tr element.
439
- */
440
- previousItemElement: HTMLElement
441
- /**
442
- * Returns the previous selected item as JSON Object from the data source.
443
- */
444
- previousItemData: { text: string, value: string }
445
- /**
446
- * Returns the selected value
447
- *
448
- * @isGenericType true
449
- */
450
- value: number | string
451
- /**
452
- * Returns the selected row data.
453
- */
454
- item: Object
455
- }
456
-
457
- export interface ResizeArgs {
458
- /**
459
- * Defines the details about the column that is currently being resized.
460
- */
461
- column: ColumnModel
462
-
463
- /**
464
- * Specifies whether to cancel the resizing operation of the columns.
465
- *
466
- * @default false
467
- */
468
- cancel: boolean
469
- }
470
-
471
- /**
472
- * @hidden
473
- */
474
- export interface DataResult {
475
- result: Object[] | Group[];
476
- count: number;
477
- aggregates?: object;
478
- }
479
-
480
- /**
481
- * The `MultiColumnComboBox` allows the user to search and select values from a list. It provides a list of options that can be selected using a filter input.
482
- * The selected value will be displayed in the input element.
483
- *
484
- * ```html
485
- * <input type='text' id='multi-column'></input>
486
- * ```
487
- * ```typescript
488
- * let multiColObj: MultiColumnComboBox = new MultiColumnComboBox();
489
- * multiColObj.appendTo('#multi-column');
490
- * ```
491
- */
492
-
493
- @NotifyPropertyChanges
494
- export class MultiColumnComboBox extends Component<HTMLElement> implements INotifyPropertyChanged {
495
-
496
- /**
497
- * Accepts the list items either through local or remote service and binds it to the component.
498
- * It can be an array of JSON Objects or an instance of `DataManager`.
499
- *
500
- * {% codeBlock src='multicolumn-combobox/value/index.md' %}{% endcodeBlock %}
501
- *
502
- * @default []
503
- * @isGenericType true
504
- */
505
- @Property([])
506
- public dataSource: Object | DataManager | DataResult;
507
-
508
- /**
509
- * Gets or sets the display text of the selected item.
510
- *
511
- * @default null
512
- */
513
- @Property(null)
514
- public text: string;
515
-
516
- /**
517
- * Gets or sets the value of the selected item.
518
- *
519
- * {% codeBlock src='multicolumn-combobox/value/index.md' %}{% endcodeBlock %}
520
- *
521
- * @default null
522
- */
523
- @Property(null)
524
- public value: string;
525
-
526
- /**
527
- * Gets or sets the index of the selected item in the component.
528
- *
529
- * @default null
530
- */
531
- @Property(null)
532
- public index: number | null;
533
-
534
- /**
535
- * Specifies the width of the component. By default, the component width sets based on the width of its parent container.
536
- *
537
- * @default '100%'
538
- * @aspType string
539
- */
540
- @Property('100%')
541
- public width: string | number;
542
-
543
- /**
544
- * Specifies the height of the popup list.
545
- *
546
- * @default '300px'
547
- * @aspType string
548
- */
549
- @Property('300px')
550
- public popupHeight: string | number;
551
-
552
- /**
553
- * Specifies the width of the popup list. By default, the popup width sets based on the width of the component.
554
- *
555
- * @default '100%'
556
- * @aspType string
557
- */
558
- @Property('100%')
559
- public popupWidth: string | number;
560
-
561
- /**
562
- * Specifies a short hint that describes the expected value of the multicolumn combobox component.
563
- *
564
- * @default null
565
- */
566
- @Property(null)
567
- public placeholder: string;
568
-
569
- /**
570
- * Specifies the filter action retrieves matched items through the filtering event based on the characters typed in the search TextBox.
571
- * If no match is found, the value of the noRecordsTemplate property will be displayed.
572
- *
573
- * {% codeBlock src='multicolumn-combobox/allowFiltering/index.md' %}{% endcodeBlock %}
574
- *
575
- * @default true
576
- */
577
- @Property(true)
578
- public allowFiltering: boolean;
579
-
580
- /**
581
- * Specifies whether sorting is allowed for the columns in the dropdown list.
582
- *
583
- * @default true
584
- */
585
- @Property(true)
586
- public allowSorting: boolean;
587
-
588
- /**
589
- * Specifies whether to show or hide the clear icon in textbox.
590
- * When the clear button is clicked, `value`, `text` properties will be reset to null.
591
- *
592
- * @default false
593
- */
594
- @Property(false)
595
- public showClearButton: boolean;
596
-
597
- /**
598
- * Sets CSS classes to the root element of the component that allows customization of appearance.
599
- *
600
- * @default ''
601
- */
602
- @Property('')
603
- public cssClass: string;
604
-
605
- /**
606
- * The `fields` property maps the columns of the data table and binds the data to the component.
607
- * * text - Maps the text column from data table for each list item.
608
- * * value - Maps the value column from data table for each list item.
609
- * * groupBy - Group the list items with it's related items by mapping groupBy field.
610
- *
611
- * {% codeBlock src='multicolumn-combobox/fields/index.md' %}{% endcodeBlock %}
612
- *
613
- * @default {text: null, value: null, groupBy: null}
614
- */
615
- @Complex<FieldSettingsModel>({ text: null, value: null, groupBy: null }, FieldSettings)
616
- public fields: FieldSettingsModel;
617
-
618
- /**
619
- * Specifies the number of columns and its respective fields to be displayed in the dropdown popup.
620
- *
621
- * {% codeBlock src='multicolumn-combobox/fields/index.md' %}{% endcodeBlock %}
622
- *
623
- * @default []
624
- */
625
- @Collection<ColumnModel[]>([], Column)
626
- public columns: ColumnModel[];
627
-
628
- /**
629
- * Specifies the configuration of the columns in the popup content.
630
- *
631
- * {% codeBlock src='multicolumn-combobox/gridSettings/index.md' %}{% endcodeBlock %}
632
- *
633
- * @default {rowHeight: null, gridLines: Default, enableAltRow: false}
634
- */
635
- @Complex<GridSettingsModel>({}, GridSettings)
636
- public gridSettings: GridSettingsModel;
637
-
638
- /**
639
- * Determines on which filter type, the component needs to be considered on search action.
640
- * The `FilterType` and its supported data types are
641
- *
642
- * <table>
643
- * <tr>
644
- * <td colSpan=1 rowSpan=1>
645
- * FilterType<br/></td><td colSpan=1 rowSpan=1>
646
- * Description<br/></td><td colSpan=1 rowSpan=1>
647
- * Supported Types<br/></td></tr>
648
- * <tr>
649
- * <td colSpan=1 rowSpan=1>
650
- * StartsWith<br/></td><td colSpan=1 rowSpan=1>
651
- * Checks whether a value begins with the specified value.<br/></td><td colSpan=1 rowSpan=1>
652
- * String<br/></td></tr>
653
- * <tr>
654
- * <td colSpan=1 rowSpan=1>
655
- * EndsWith<br/></td><td colSpan=1 rowSpan=1>
656
- * Checks whether a value ends with specified value.<br/><br/></td><td colSpan=1 rowSpan=1>
657
- * <br/>String<br/></td></tr>
658
- * <tr>
659
- * <td colSpan=1 rowSpan=1>
660
- * Contains<br/></td><td colSpan=1 rowSpan=1>
661
- * Checks whether a value contains with specified value.<br/><br/></td><td colSpan=1 rowSpan=1>
662
- * <br/>String<br/></td></tr>
663
- * </table>
664
- *
665
- * The default value set to `StartsWith`, all the suggestion items which contain typed characters to listed in the suggestion popup.
666
- *
667
- * {% codeBlock src='multicolumn-combobox/allowFiltering/index.md' %}{% endcodeBlock %}
668
- *
669
- * @isenumeration true
670
- * @default FilterType.StartsWith
671
- * @asptype FilterType
672
- */
673
- @Property(FilterType.StartsWith)
674
- public filterType: FilterType | string;
675
-
676
- /**
677
- * Specifies whether to display the floating label above the input element.
678
- * Possible values are:
679
- * * Never - The label will never float in the input when the placeholder is available.
680
- * * Always - The floating label will always float above the input.
681
- * * Auto - The floating label will float above the input after focusing or entering a value in the input.
682
- *
683
- * {% codeBlock src='multicolumn-combobox/floatLabelType/index.md' %}{% endcodeBlock %}
684
- *
685
- * @default Never
686
- */
687
- @Property('Never')
688
- public floatLabelType: FloatLabelType;
689
-
690
- /**
691
- * Specifies the sortOrder to sort the data source.
692
- * The available type of sort orders are,
693
- * * `None` - The datasource is not sorting. Default value is None.
694
- * * `Ascending` - The datasource is sorting with ascending order.
695
- * * `Descending` - The data source is sorting with descending order.
696
- *
697
- * @isenumeration true
698
- * @default SortOrder.None
699
- * @asptype SortOrder
700
- */
701
- @Property(SortOrder.None)
702
- public sortOrder: SortOrder | string;
703
-
704
- /**
705
- * Specifies the type of sorting to be applied for the columns.
706
- * * `OneColumn` - Allow sorting only one column.
707
- * * `MultipleColumns` - Allow sorting multiple columns.
708
- *
709
- * @isenumeration true
710
- * @default SortType.OneColumn
711
- * @asptype SortType
712
- */
713
- @Property(SortType.OneColumn)
714
- public sortType: SortType | string;
715
-
716
- /**
717
- * Defines whether to enable virtual scrolling in the component.
718
- *
719
- * @default false
720
- */
721
- @Property(false)
722
- public enableVirtualization: boolean;
723
-
724
- /**
725
- * Specifies a value that indicates whether the component is disabled or not.
726
- *
727
- * @default false
728
- */
729
- @Property(false)
730
- public disabled: boolean;
731
-
732
- /**
733
- * Specifies the user interactions on the component are disabled.
734
- *
735
- * @default false
736
- */
737
- @Property(false)
738
- public readonly: boolean;
739
-
740
- /**
741
- * Specifies the component’s state between page reloads. If enabled, the list of states for the value will be persisted.
742
- *
743
- * @default false
744
- */
745
- @Property(false)
746
- public enablePersistence: boolean;
747
-
748
- /**
749
- * Accepts the external Query that execute along with data processing.
750
- *
751
- * {% codeBlock src='multicolumn-combobox/query/index.md' %}{% endcodeBlock %}
752
- *
753
- * @default null
754
- */
755
- @Property()
756
- public query: Query;
757
-
758
- /**
759
- * Accepts the template design and assigns it to each items present in the popup.
760
- *
761
- * {% codeBlock src='multicolumn-combobox/itemTemplate/index.md' %}{% endcodeBlock %}
762
- *
763
- * @default null
764
- * @angularType string | object
765
- * @reactType string | function | JSX.Element
766
- * @vueType string | function
767
- * @aspType string
768
- */
769
- @Property(null)
770
- public itemTemplate: string | Function;
771
-
772
- /**
773
- * Accepts the template design and assigns it to the footer container of the popup.
774
- *
775
- * @default null
776
- * @angularType string | object
777
- * @reactType string | function | JSX.Element
778
- * @vueType string | function
779
- * @aspType string
780
- */
781
- @Property(null)
782
- public footerTemplate: string | Function;
783
-
784
- /**
785
- * Accepts the template design and assigns it to the group headers present in the popup list.
786
- *
787
- * @default null
788
- * @angularType string | object
789
- * @reactType string | function | JSX.Element
790
- * @vueType string | function
791
- * @aspType string
792
- */
793
- @Property(null)
794
- public groupTemplate: string | Function;
795
-
796
- /**
797
- * Accepts the template and assigns it to the popup content when the data fetch request from the remote server fails.
798
- *
799
- * @default 'Request Failed'
800
- * @angularType string | object
801
- * @reactType string | function | JSX.Element
802
- * @vueType string | function
803
- * @aspType string
804
- */
805
- @Property('Request Failed')
806
- public actionFailureTemplate: string | Function;
807
-
808
- /**
809
- * Accepts the template design and assigns it to popup list of component when no data is available on the component.
810
- *
811
- * @default 'No records found'
812
- * @angularType string | object
813
- * @reactType string | function | JSX.Element
814
- * @vueType string | function
815
- * @aspType string
816
- */
817
- @Property('No records found')
818
- public noRecordsTemplate: string | Function;
819
-
820
- /**
821
- * Allows additional HTML attributes such as title, name, etc., and accepts n number of attributes in a key-value pair format.
822
- *
823
- * {% codeBlock src='multicolumn-combobox/htmlAttributes/index.md' %}{% endcodeBlock %}
824
- *
825
- * @default {}
826
- */
827
- @Property({})
828
- public htmlAttributes: { [key: string]: string; };
829
-
830
- /**
831
- * Event callback that is raised after rendering the control.
832
- *
833
- * @event created
834
- */
835
- @Event()
836
- public created: EmitType<Event>;
837
-
838
- /**
839
- * Triggers when the popup opens.
840
- *
841
- * @event open
842
- */
843
- @Event()
844
- public open: EmitType<PopupEventArgs>;
845
- /**
846
- * Triggers when the popup is closed.
847
- *
848
- * @event close
849
- */
850
- @Event()
851
- public close: EmitType<PopupEventArgs>;
852
-
853
- /**
854
- * Triggers when the data fetch request from the remote server fails.
855
- *
856
- * @event actionFailure
857
- */
858
- @Event()
859
- public actionFailure: EmitType<Object>;
860
-
861
- /**
862
- * Triggers before fetching data from the remote server.
863
- *
864
- * @event actionBegin
865
- */
866
- @Event()
867
- public actionBegin: EmitType<Object>;
868
-
869
- /**
870
- * Triggers after data is fetched successfully from the remote server.
871
- *
872
- * @event actionComplete
873
- */
874
- @Event()
875
- public actionComplete: EmitType<Object>;
876
-
877
- /**
878
- * Triggers on typing a character in the component.
879
- *
880
- * @event filtering
881
- */
882
- @Event()
883
- public filtering: EmitType<FilteringEventArgs>;
884
-
885
- /**
886
- * Triggers when an item in the popup is selected by the user either with mouse/tap or with keyboard navigation.
887
- *
888
- * @event select
889
- */
890
- @Event()
891
- public select: EmitType<SelectEventArgs>;
892
-
893
- /**
894
- * Triggers when an item in a popup is selected or when the model value is changed by the user.
895
- *
896
- * @event change
897
- */
898
- @Event()
899
- public change: EmitType<ChangeEventArgs>;
900
-
901
- /* Private variables */
902
- private dropdownElement: HTMLElement;
903
- private inputEle: HTMLInputElement;
904
- private inputObj: InputObject;
905
- private inputWrapper: HTMLElement;
906
- private popupDiv: HTMLElement;
907
- private popupEle: HTMLElement;
908
- private popupObj: Popup;
909
- private gridObj: Grid;
910
- private gridEle: HTMLElement;
911
- private isPopupOpen: boolean;
912
- private footer: HTMLElement;
913
- private l10n: L10n;
914
- private noRecord: HTMLElement;
915
- private previousItemElement: HTMLElement;
916
- private keyboardModule: KeyboardEvents;
917
- private keyConfigs: { [key: string]: string };
918
- private gridInject: MultiColumnGrid = new MultiColumnGrid();
919
- private prevGridHeight: number;
920
- private popupRowHeight: number;
921
- private matchedRowEle: Element;
922
- private matchedContent: { [key: string]: Object } | undefined;
923
- private exactMatchedContent: { [key: string]: Object } | undefined;
924
- private isDataFiltered: boolean;
925
- private isInitialRender: boolean;
926
- private remoteDataLength: number;
927
- private selectedRowIndex: number;
928
- private isShowSpinner: boolean = true;
929
- private hiddenElement: HTMLSelectElement;
930
- private isLocaleChanged: boolean;
931
- private gridData: Object | DataManager | DataResult;
932
- private mainData: Object | DataManager | DataResult;
933
- private isMainDataUpdated: boolean;
934
- private isCustomFilter: boolean;
935
- private customFilterQuery: Query;
936
- private typedString: string;
937
-
938
- /**
939
- * *Constructor for creating the component
940
- *
941
- * @param {MultiColumnComboBoxModel} options - Specifies the MultiColumnComboBox model.
942
- * @param {string | HTMLElement} element - Specifies the element to render as component.
943
- * @private
944
- */
945
- public constructor(options?: MultiColumnComboBoxModel, element?: string | HTMLElement) {
946
- super(options, element);
947
- this.gridInject.InjectModules();
948
- }
949
- /**
950
- * Initialize the event handler
951
- *
952
- * @private
953
- * @returns {void}
954
- */
955
- protected preRender(): void {
956
- if (!this.element.id) { this.element.id = getUniqueID('e-' + this.getModuleName()); }
957
- this.keyConfigs = {
958
- escape: 'escape',
959
- altUp: 'alt+uparrow',
960
- altDown: 'alt+downarrow',
961
- tab: 'tab',
962
- shiftTab: 'shift+tab',
963
- end: 'end',
964
- enter: 'enter',
965
- home: 'home',
966
- moveDown: 'downarrow',
967
- moveUp: 'uparrow'
968
- };
969
- this.matchedRowEle = this.matchedContent = this.exactMatchedContent = null;
970
- this.persistData();
971
- }
972
-
973
- protected getDirective(): string {
974
- return 'EJS-MULTICOLUMNCOMBOBOX';
975
- }
976
-
977
- /**
978
- * To get component name.
979
- *
980
- * @returns {string} - It returns the current module name.
981
- * @private
982
- */
983
- public getModuleName(): string {
984
- return 'multicolumncombobox';
985
- }
986
-
987
- /**
988
- * Get the properties to be maintained in the persisted state.
989
- *
990
- * @private
991
- * @returns {string} - It returns the persisted data.
992
- */
993
- protected getPersistData(): string {
994
- return this.addOnPersist(['value']);
995
- }
996
-
997
- private persistData (): void {
998
- if (this.enablePersistence) {
999
- this.element.id += '_wrapper';
1000
- const data: string = window.localStorage.getItem(this.getModuleName() + this.element.id);
1001
- if (!(isNOU(data) || (data === ''))) {
1002
- this.setProperties(JSON.parse(data), true);
1003
- }
1004
- }
1005
- }
1006
-
1007
- protected render(): void {
1008
- this.renderInput();
1009
- if (this.gridData == null) {
1010
- this.setGridData(this.dataSource);
1011
- }
1012
- this.renderGrid();
1013
- this.popupDiv = this.createElement('div', { className: CONTENT });
1014
- this.popupDiv.appendChild(this.gridEle);
1015
- this.setHTMLAttributes();
1016
- this.renderPopup();
1017
- this.wireEvents();
1018
- }
1019
-
1020
- private setGridData(dataSource: Object | DataManager, query?: Query): void {
1021
- this.trigger('actionBegin', { cancel: false, query: query }, (args: { [key: string]: Object }) => {
1022
- if (!args.cancel) {
1023
- if (dataSource instanceof DataManager) {
1024
- if (this.isShowSpinner) {
1025
- this.showHideSpinner(true);
1026
- }
1027
- (dataSource as DataManager).executeQuery(this.getQuery(query as Query)).then((e: Object) => {
1028
- this.gridData = (e as any).result;
1029
- this.trigger('actionComplete', e, (e: Object) => {
1030
- this.showHideSpinner(false);
1031
- if (!this.isMainDataUpdated) {
1032
- this.mainData = this.gridData;
1033
- this.isMainDataUpdated = true;
1034
- }
1035
- if (this.popupDiv) {
1036
- this.updateGridDataSource();
1037
- }
1038
- });
1039
- }).catch((e: any) => {
1040
- this.trigger('actionFailure', e, null);
1041
- });
1042
- } else {
1043
- const dataManager: DataManager = new DataManager(dataSource as DataOptions | JSON[]);
1044
- const listItems: { [key: string]: Object }[] = <{ [key: string]: Object }[]>(
1045
- this.getQuery(query as Query)).executeLocal(dataManager);
1046
- this.gridData = listItems;
1047
- this.trigger('actionComplete', { result: listItems }, (e: Object) => {
1048
- if (!this.isMainDataUpdated) {
1049
- this.mainData = this.gridData;
1050
- this.isMainDataUpdated = true;
1051
- }
1052
- if (this.popupDiv) {
1053
- this.updateGridDataSource();
1054
- }
1055
- });
1056
- }
1057
- }
1058
- });
1059
- }
1060
-
1061
- protected getQuery(query: Query): Query {
1062
- let filterQuery: Query;
1063
- if (!this.isCustomFilter && this.allowFiltering) {
1064
- filterQuery = query ? query.clone() : this.query ? this.query.clone() : new Query();
1065
- const filterType: string = this.typedString === '' ? 'contains' : this.filterType;
1066
- if ((this.allowFiltering && this.typedString && this.typedString !== '')) {
1067
- const fields: string = (this.fields.text) ? this.fields.text : '';
1068
- filterQuery.where(fields, filterType, this.typedString, true, false);
1069
- }
1070
- } else {
1071
- filterQuery = (this.customFilterQuery != null) ?
1072
- this.customFilterQuery.clone() : query ? query.clone() : this.query ? this.query.clone() : new Query();
1073
- }
1074
- return filterQuery;
1075
- }
1076
-
1077
- private setHiddenValue(): void {
1078
- if (isNOU(this.value)) {
1079
- this.hiddenElement.innerHTML = '';
1080
- return;
1081
- }
1082
- const existingOption: HTMLOptionElement = this.hiddenElement.querySelector('option');
1083
- if (!isNOU(existingOption)) {
1084
- existingOption.textContent = this.text;
1085
- existingOption.setAttribute('value', this.value.toString());
1086
- } else if (!isNOU(this.hiddenElement)) {
1087
- const newOption: HTMLOptionElement = document.createElement('option');
1088
- newOption.text = this.text;
1089
- newOption.setAttribute('value', this.value.toString());
1090
- newOption.setAttribute('selected', '');
1091
- this.hiddenElement.appendChild(newOption);
1092
- }
1093
- }
1094
-
1095
- private renderGrid(): void {
1096
- const gridColumns: ColumnModel[] = this.getGridColumns();
1097
- const sortOrder: string = this.sortOrder.toString().toLowerCase();
1098
- this.gridObj = new Grid({
1099
- dataSource: this.gridData,
1100
- columns: gridColumns,
1101
- allowSorting: this.allowSorting,
1102
- enableStickyHeader: true,
1103
- gridLines: this.gridSettings.gridLines,
1104
- rowHeight: this.gridSettings.rowHeight,
1105
- enableAltRow: this.gridSettings.enableAltRow,
1106
- enableVirtualization: this.enableVirtualization,
1107
- enableRtl: this.enableRtl,
1108
- editSettings: { allowAdding: false },
1109
- allowTextWrap: this.gridSettings.allowTextWrap,
1110
- textWrapSettings: { wrapMode: this.gridSettings.textWrapMode as WrapMode },
1111
- height: this.popupHeight,
1112
- allowResizing: this.gridSettings.allowResizing,
1113
- allowMultiSorting: this.sortType.toString().toLowerCase() === 'multiplecolumns' && this.allowSorting,
1114
- rowTemplate: this.itemTemplate,
1115
- beforeDataBound: () => {
1116
- if (this.dataSource instanceof DataManager && this.isShowSpinner) {
1117
- this.showHideSpinner(true);
1118
- this.isShowSpinner = false;
1119
- }
1120
- },
1121
- dataBound: () => { this.onDataBound(); },
1122
- actionFailure: (args: FailureEventArgs) => { this.onActionFailure(args); },
1123
- actionComplete: this.handleActionComplete.bind(this),
1124
- keyPressed: this.handleKeyPressed.bind(this),
1125
- resizing: (args: ResizeArgs) => {
1126
- if (this.gridSettings.resizing) {
1127
- this.gridSettings.resizing.call(this, args);
1128
- }
1129
- },
1130
- resizeStart: (args: ResizeArgs) => {
1131
- if (this.gridSettings.resizeStart) {
1132
- this.gridSettings.resizeStart.call(this, args);
1133
- }
1134
- },
1135
- resizeStop: (args: ResizeArgs) => {
1136
- if (this.gridSettings.resizeStop) {
1137
- this.gridSettings.resizeStop.call(this, args);
1138
- }
1139
- }
1140
- });
1141
- this.gridEle = this.createElement('div', { id: `${this.element.id}_${getUniqueID('grid')}`, className: MULTICOLUMNGRID });
1142
- this.updateGroupByField();
1143
- if (gridColumns.length > 0) {
1144
- // Set first column as primary key to avoid PRIMARY KEY MISSING warning.
1145
- (this.gridObj.columns[0] as GridColumnModel).isPrimaryKey = true;
1146
- }
1147
- if (sortOrder !== 'none') {
1148
- this.gridObj.sortSettings = { columns: [{ field: this.fields.text, direction: sortOrder === 'ascending' ?
1149
- SortOrder.Ascending : SortOrder.Descending }] };
1150
- }
1151
- this.gridObj.appendTo(this.gridEle);
1152
- if (!isNOU(this.value) || !isNOU(this.text) || !isNOU(this.index)) { this.initValue(null, null, true); }
1153
- }
1154
-
1155
- private handleActionComplete(args: { [key: string]: Object }): void {
1156
- if (args.requestType === 'sorting') {
1157
- this.updateRowSelection(args);
1158
- }
1159
- if (Array.isArray(args.rows) && this.isDataFiltered) {
1160
- const rows: Array<{ uid: string }> = args.rows as Array<{ uid: string }>;
1161
- let rowHeight: number = 0;
1162
- rows.forEach((row: { uid: string }) => {
1163
- const rowElement: Element | null = this.gridObj.getRowElementByUID(row.uid);
1164
- if (rowElement) {
1165
- rowHeight += rowElement.getBoundingClientRect().height;
1166
- }
1167
- });
1168
- this.popupRowHeight = rowHeight || parseFloat(this.popupHeight as string);
1169
- this.updateGridHeight(true, true);
1170
- }
1171
- this.popupObj.refreshPosition();
1172
- this.gridObj.element.querySelector('.e-content').scrollTop = 0;
1173
- }
1174
-
1175
- private handleKeyPressed(args: KeyboardEventArgs): void {
1176
- if (args.key === 'Enter') {
1177
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1178
- (args as any).cancel = true;
1179
- if (this.isPopupOpen) {
1180
- this.selectedGridRow(this.gridObj.getRows()[this.gridObj.selectedRowIndex], args, true);
1181
- this.hidePopup(args);
1182
- this.focusIn(args);
1183
- }
1184
- }
1185
- if (this.fields.groupBy) {
1186
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1187
- (args as any).cancel = true;
1188
- this.gridKeyActionHandler(args, true);
1189
- }
1190
- }
1191
-
1192
- /* eslint-disable @typescript-eslint/no-explicit-any */
1193
- private isRowMatching(data: any, selectedValue: string, selectedText: string): boolean {
1194
- const flattenData: Function = (data: any): string[] => {
1195
- const result: string[] = [];
1196
- if (data && typeof data === 'object') {
1197
- if (Array.isArray(data)) { data.forEach((item: any) => result.push(...flattenData(item))); }
1198
- else { Object.keys(data).forEach((key: string) => result.push(...flattenData(data[`${key}`]))); }
1199
- } else if (data != null) { result.push(String(data)); }
1200
- return result;
1201
- };
1202
- const flattenedValues: string[] = flattenData(data);
1203
- return (flattenedValues.indexOf(selectedValue) !== -1 && flattenedValues.indexOf(selectedText) !== -1);
1204
- }
1205
-
1206
- private updateRowSelection(args: any): void {
1207
- if (args) {
1208
- const dataRows: { [key: string]: object }[] = args.rows;
1209
- dataRows.forEach((row: any) => {
1210
- this.selectDataRow(row.data, row.index);
1211
- });
1212
- }
1213
- }
1214
-
1215
- private selectDataRow(data: any, index: number): void {
1216
- const isPresent: boolean = this.isRowMatching(data, this.value ?
1217
- this.value.toString() : '', this.text ? this.text.toString() : '');
1218
- if (isPresent) {
1219
- this.gridObj.selectRow(index);
1220
- const prevOnChange: boolean = this.isProtectedOnChange;
1221
- this.isProtectedOnChange = true;
1222
- this.index = index;
1223
- this.isProtectedOnChange = prevOnChange;
1224
- return;
1225
- }
1226
- }
1227
-
1228
- private findIndex(arr: Object[], obj: { [key: string]: object }): number {
1229
- return arr.findIndex((item: Object) => {
1230
- // eslint-disable-next-line
1231
- return Object.keys(obj).every((key: string) => (item as any)[key] === obj[key]);
1232
- });
1233
- }
1234
-
1235
- private getGridColumns(): ColumnModel[] {
1236
- return this.columns.map(({ field, header, width, textAlign, format, displayAsCheckBox, template,
1237
- headerTemplate, customAttributes }: ColumnModel) => ({
1238
- field,
1239
- headerText: header,
1240
- width,
1241
- textAlign: textAlign.toString() === '' && this.enableRtl ? 'Right' : textAlign,
1242
- format,
1243
- displayAsCheckBox,
1244
- template,
1245
- headerTemplate,
1246
- customAttributes,
1247
- type: displayAsCheckBox && !format ? 'boolean' : undefined
1248
- }));
1249
- }
1250
-
1251
- private updateGroupByField(): void {
1252
- const groupByField: string = this.fields.groupBy;
1253
- const isGroupByValid: boolean = groupByField !== '' && !isNOU(groupByField);
1254
- if (isGroupByValid) {
1255
- if (this.sortType.toString().toLowerCase() !== 'multiplecolumns') { this.gridEle.classList.add('e-multicolumn-group'); }
1256
- const prevOnChange: boolean = this.isProtectedOnChange;
1257
- this.isProtectedOnChange = true;
1258
- this.gridObj.allowGrouping = true;
1259
- this.gridObj.groupSettings = {
1260
- showDropArea: false,
1261
- columns: [groupByField]
1262
- };
1263
- if (this.groupTemplate && isGroupByValid) {
1264
- this.gridObj.groupSettings.captionTemplate = this.groupTemplate;
1265
- }
1266
- if (this.isVue) {
1267
- this.gridObj.isVue = this.isVue;
1268
- }
1269
- this.isProtectedOnChange = prevOnChange;
1270
- }
1271
- }
1272
-
1273
- private onDataBound(): void {
1274
- if (this.isLocaleChanged) {
1275
- this.isLocaleChanged = false;
1276
- this.unWireEvents();
1277
- this.wireEvents();
1278
- }
1279
- const dataCount: number = (<{ [key: string]: Object }[]>this.dataSource).length;
1280
- const popupChild: HTMLElement = this.popupDiv.querySelector('.' + MULTICOLUMNGRID);
1281
- const hasNoDataClass: boolean = this.popupDiv.classList.contains(NODATA);
1282
- if (dataCount <= 0 && popupChild) {
1283
- this.l10nUpdate();
1284
- this.popupDiv.removeChild(this.gridEle);
1285
- addClass([this.popupDiv], [NODATA]);
1286
- } else if (hasNoDataClass && dataCount >= 1) {
1287
- removeClass([this.popupDiv], [NODATA]);
1288
- const noRecordEle: HTMLElement = this.popupDiv.querySelector('.e-no-records');
1289
- if (noRecordEle) { this.popupDiv.removeChild(noRecordEle); }
1290
- }
1291
- if (this.isInitialRender) {
1292
- const gridContentRow: HTMLElement | null = this.popupDiv.querySelector('.e-gridcontent tr');
1293
- const rowHeight: number = !hasNoDataClass ? gridContentRow ?
1294
- gridContentRow.getBoundingClientRect().height : 0 :
1295
- this.popupDiv.getBoundingClientRect().height;
1296
- this.popupRowHeight = rowHeight;
1297
- this.popupObj.hide();
1298
- this.popupEle.style.visibility = 'unset';
1299
- this.isInitialRender = false;
1300
- }
1301
- const rowElements: NodeListOf<Element> = this.gridObj.element.querySelectorAll('.e-row');
1302
- if (this.isDataFiltered && rowElements.length > 0 && this.inputEle.value !== '') {
1303
- const firstRowEle: Element = rowElements[0];
1304
- firstRowEle.classList.add('e-row-focus');
1305
- }
1306
- if (this.dataSource instanceof DataManager) {
1307
- setTimeout((): void => {
1308
- this.showHideSpinner(false);
1309
- });
1310
- }
1311
- }
1312
-
1313
- private showHideSpinner(isShow: boolean): void {
1314
- if (isShow) { showSpinner(this.dropdownElement); }
1315
- else { hideSpinner(this.dropdownElement); }
1316
- }
1317
-
1318
- private onActionFailure(args: FailureEventArgs): void {
1319
- this.trigger('actionFailure', args);
1320
- this.l10nUpdate(true);
1321
- addClass([this.popupDiv], [NODATA]);
1322
- }
1323
-
1324
- private renderInput(): void {
1325
- const allowedAttributes: string[] = ['aria-expanded', 'aria-readOnly', 'aria-disabled', 'autocomplete',
1326
- 'autocapitalize', 'spellcheck', 'tabindex'];
1327
- const setAttributes: Function = (element: HTMLElement, attributes: { [key: string]: string }) => {
1328
- for (const key in attributes) {
1329
- // eslint-disable-next-line no-prototype-builtins
1330
- if (attributes.hasOwnProperty(key) && allowedAttributes.indexOf(key) !== -1 && isNOU(element.getAttribute(key))) {
1331
- element.setAttribute(key, attributes[key as string]);
1332
- }
1333
- }
1334
- };
1335
- if (this.element.tagName === 'INPUT') {
1336
- this.inputEle = this.element as HTMLInputElement;
1337
- if (isNOU(this.inputEle.getAttribute('role'))) { this.inputEle.setAttribute('role', 'combobox'); }
1338
- if (isNOU(this.inputEle.getAttribute('type'))) { this.inputEle.setAttribute('type', 'text'); }
1339
- setAttributes(this.inputEle, {
1340
- 'aria-expanded': 'false',
1341
- 'aria-readOnly': this.readonly.toString(),
1342
- 'aria-disabled': this.disabled.toString(),
1343
- autocomplete: 'off',
1344
- autocapitalize: 'off',
1345
- spellcheck: 'false',
1346
- tabindex: '0'
1347
- });
1348
- } else {
1349
- this.inputEle = this.createElement('input', { attrs: { role: 'textbox', type: 'text' } }) as HTMLInputElement;
1350
- this.element.parentElement.insertBefore(this.inputEle, this.element);
1351
- }
1352
- this.inputObj = Input.createInput({
1353
- element: this.inputEle,
1354
- buttons: [DROPDOWNICON],
1355
- floatLabelType: this.floatLabelType,
1356
- properties: {
1357
- enabled: !this.disabled,
1358
- readonly: this.readonly,
1359
- placeholder: this.placeholder,
1360
- enableRtl: this.enableRtl,
1361
- showClearButton: this.showClearButton,
1362
- cssClass: this.cssClass
1363
- }
1364
- }, this.createElement);
1365
- this.inputWrapper = this.inputObj.container;
1366
- this.inputWrapper.classList.add(MULTICOLUMNLIST);
1367
- this.inputWrapper.setAttribute('spellcheck', 'false');
1368
- this.hiddenElement = this.createElement('select', {
1369
- attrs: {
1370
- 'aria-hidden': 'true',
1371
- 'tabindex': '-1',
1372
- 'class': HIDDENELEMENT
1373
- }
1374
- }) as HTMLSelectElement;
1375
- prepend([this.hiddenElement], this.inputWrapper);
1376
- const name: string = this.inputEle.getAttribute('name') ? this.inputEle.getAttribute('name') : this.inputEle.getAttribute('id');
1377
- this.hiddenElement.setAttribute('name', name);
1378
- this.inputEle.removeAttribute('name');
1379
- if (!this.hiddenElement.hasAttribute('aria-label')) {
1380
- this.hiddenElement.setAttribute('aria-label', this.getModuleName());
1381
- }
1382
- if (this.element.tagName === this.getDirective()) {
1383
- this.element.appendChild(this.inputWrapper);
1384
- }
1385
- this.setElementWidth(this.width);
1386
- this.dropdownElement = this.inputWrapper.querySelector('.e-input-group-icon.e-multicolumn-list-icon.e-icons');
1387
- createSpinner({
1388
- target: this.dropdownElement
1389
- });
1390
- }
1391
-
1392
- private setElementWidth(inputWidth: string | number): void {
1393
- if (isNOU(inputWidth)) { return; }
1394
- const ddElement: HTMLElement = this.inputWrapper;
1395
- if (typeof inputWidth === 'number') { ddElement.style.width = formatUnit(inputWidth); }
1396
- else if (typeof inputWidth === 'string') {
1397
- ddElement.style.width = inputWidth.match(/px|%|em/) ? inputWidth : formatUnit(inputWidth);
1398
- }
1399
- }
1400
-
1401
- private setHTMLAttributes(): void {
1402
- const htmlAttributes: { [key: string]: string } = this.htmlAttributes;
1403
- const inputEle: HTMLInputElement = this.inputEle;
1404
- if (Object.keys(htmlAttributes).length) {
1405
- for (const htmlAttr of Object.keys(htmlAttributes)) {
1406
- switch (htmlAttr) {
1407
- case 'class':
1408
- this.inputWrapper.classList.add(htmlAttributes[htmlAttr as string]);
1409
- break;
1410
- case 'disabled':
1411
- this.setProperties({ enabled: false }, true);
1412
- this.setEnable();
1413
- break;
1414
- case 'readonly':
1415
- this.setProperties({ readonly: true }, true);
1416
- this.dataBind();
1417
- break;
1418
- case 'style': {
1419
- const styles: string = htmlAttributes[htmlAttr as string];
1420
- this.inputWrapper.style.cssText = '';
1421
- if (styles) {
1422
- styles.split(';').forEach((styleProperty: string) => {
1423
- const [property, value] = styleProperty.split(':').map((part: string) => part.trim());
1424
- if (property && value) {
1425
- this.inputWrapper.style.setProperty(property, value);
1426
- }
1427
- });
1428
- }
1429
- break;
1430
- }
1431
- default: {
1432
- const defaultAttr: string[] = ['title', 'id', 'placeholder', 'role', 'autocomplete', 'autocapitalize', 'spellcheck', 'minlength', 'maxlength'];
1433
- const validateAttr: string[] = ['name', 'required'];
1434
- if (validateAttr.indexOf(htmlAttr) > -1 || htmlAttr.indexOf('data') === 0) {
1435
- this.hiddenElement.setAttribute(htmlAttr, this.htmlAttributes[`${htmlAttr}`]);
1436
- } else if (defaultAttr.indexOf(htmlAttr) > -1) {
1437
- if (htmlAttr === 'placeholder') {
1438
- Input.setPlaceholder(htmlAttributes[htmlAttr as string], inputEle);
1439
- } else {
1440
- inputEle.setAttribute(htmlAttr, htmlAttributes[htmlAttr as string]);
1441
- }
1442
- } else {
1443
- inputEle.setAttribute(htmlAttr, htmlAttributes[htmlAttr as string]);
1444
- }
1445
- break;
1446
- }
1447
- }
1448
- }
1449
- }
1450
- }
1451
-
1452
- /* To set enable property */
1453
- private setEnable(): void {
1454
- Input.setEnabled(!this.disabled, this.inputEle);
1455
- if (!this.disabled) {
1456
- removeClass([this.inputWrapper], DISABLED);
1457
- this.setAriaDisabled('false');
1458
- } else {
1459
- if (this.isPopupOpen) {
1460
- this.hidePopup();
1461
- }
1462
- addClass([this.inputWrapper], DISABLED);
1463
- if (this.inputWrapper && this.inputWrapper.classList.contains(INPUTFOCUS)) {
1464
- removeClass([this.inputWrapper], [INPUTFOCUS]);
1465
- }
1466
- this.setAriaDisabled('true');
1467
- }
1468
- }
1469
-
1470
- private setAriaDisabled(value: string): void {
1471
- this.inputEle.setAttribute('aria-disabled', value);
1472
- this.inputWrapper.setAttribute('aria-disabled', value);
1473
- }
1474
-
1475
- private updateFieldValue(fieldValue: string, dataObj: object): string {
1476
- const fieldVal: string = getValue(fieldValue, dataObj).toString();
1477
- return fieldVal;
1478
- }
1479
-
1480
- private initValue(isRerender?: boolean, isValue?: boolean, isInitial?: boolean): void {
1481
- const prevItemData: { text: string, value: string } = this.gridObj.getSelectedRecords()[0] as { text: string, value: string };
1482
- const prevItemEle: HTMLElement = this.gridObj.getSelectedRows()[0] as HTMLElement;
1483
- let item: { [key: string]: Object };
1484
- let currentValue: string;
1485
- let currentText: string;
1486
- let currentIndex: number;
1487
- const prevOnChange: boolean = this.isProtectedOnChange;
1488
- this.isProtectedOnChange = true;
1489
- this.value = this.value ? this.value.toString() : this.value;
1490
- this.isProtectedOnChange = prevOnChange;
1491
- const updateValues: Function = (dataList: { [key: string]: Object }[]): void => {
1492
- const result: { currentValue: string; currentText: string; currentIndex: number; } = this.updateCurrentValues(item, dataList);
1493
- currentValue = result.currentValue;
1494
- currentText = result.currentText;
1495
- currentIndex = result.currentIndex;
1496
- };
1497
- if ((!isRerender && (!isNOU(this.value) || !isNOU(this.text))) || (isRerender && isValue !== undefined)) {
1498
- const value: string = isRerender ? (isValue ? this.value : this.text) : (!isNOU(this.value) ? this.value : this.text);
1499
- if (!isNOU(this.dataSource) && this.dataSource instanceof DataManager) {
1500
- (this.dataSource as DataManager).executeQuery(new Query).then((e: Object) => {
1501
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1502
- const dataLists: { [key: string]: Object }[] = (e as any).result;
1503
- const filteredData: { [key: string]: Object }[] = dataLists.filter((item: { [key: string]: Object }) => {
1504
- const fieldVal: string = item ? (this.updateFieldValue(isRerender ? (isValue ? this.fields.value :
1505
- this.fields.text) : !isNOU(this.value) ? this.fields.value : this.fields.text, item)) : null;
1506
- return fieldVal === value;
1507
- });
1508
- if (filteredData.length > 0) {
1509
- item = filteredData[0];
1510
- updateValues(dataLists);
1511
- this.updateChangeEvent(item, prevItemData, prevItemEle, currentValue, currentText, currentIndex,
1512
- isRerender, isInitial);
1513
- this.gridObj.selectRow(this.index);
1514
- }
1515
- });
1516
- } else if (!isNOU(this.dataSource) && this.dataSource instanceof Array) {
1517
- item = (<{ [key: string]: Object }[]>this.dataSource).filter((data: { [key: string]: Object }) => {
1518
- const fieldVal: string = this.updateFieldValue(isRerender ? (isValue ? this.fields.value : this.fields.text) :
1519
- !isNOU(this.value) ? this.fields.value : this.fields.text, data);
1520
- return fieldVal === value;
1521
- })[0];
1522
- updateValues(this.dataSource);
1523
- }
1524
- } else if (!isNOU(this.index)) {
1525
- if (!isNOU(this.dataSource) && this.dataSource instanceof DataManager) {
1526
- (this.dataSource as DataManager).executeQuery(new Query).then((e: Object) => {
1527
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1528
- const dataLists: { [key: string]: Object }[] = (e as any).result;
1529
- item = dataLists[this.index];
1530
- updateValues(dataLists);
1531
- this.updateChangeEvent(item, prevItemData, prevItemEle, currentValue, currentText, currentIndex, isRerender, isInitial);
1532
- this.gridObj.selectRow(this.index);
1533
- });
1534
- } else if (!isNOU(this.dataSource) && this.dataSource instanceof Array) {
1535
- if (!this.fields.groupBy) {
1536
- item = (<{ [key: string]: Object }[]>this.dataSource)[this.index];
1537
- updateValues(this.dataSource);
1538
- }
1539
- else {
1540
- setTimeout((): void => {
1541
- const rows: Element[] = this.gridObj.getRows();
1542
- if (rows && rows.length > 0) {
1543
- const rowData: { [key: string]: Object } =
1544
- this.gridObj.getRowInfo(rows[this.index]).rowData as { [key: string]: Object };
1545
- const value: string = this.fields.value as string;
1546
- for (let i: number = 0; i < rows.length; i++) {
1547
- if (rowData && rowData[parseInt(value.toString(), 10)] ===
1548
- (<{ [key: string]: Object }[]>this.dataSource)[parseInt(i.toString(), 10)][parseInt(value.toString(), 10)])
1549
- {
1550
- item = rowData;
1551
- updateValues(this.dataSource);
1552
- this.updateChangeEvent(item, prevItemData, prevItemEle, currentValue, currentText,
1553
- currentIndex, isRerender, isInitial);
1554
- this.gridObj.selectRow(this.index);
1555
- break;
1556
- }
1557
- }
1558
- }
1559
- });
1560
- }
1561
- }
1562
- }
1563
- if (!(this.dataSource instanceof DataManager)) {
1564
- this.updateChangeEvent(item, prevItemData, prevItemEle, currentValue, currentText, currentIndex, isRerender, isInitial);
1565
- }
1566
- }
1567
-
1568
- private updateChangeEvent(item: { [key: string]: Object }, prevItemData: { text: string, value: string }, prevItemEle: HTMLElement,
1569
- currentValue: string, currentText: string, currentIndex: number,
1570
- isRerender?: boolean, isInitial?: boolean ): void {
1571
- const fieldValue: string = item ? this.updateFieldValue(this.fields.value, item) : null;
1572
- const ChangeEventArgs: ChangeEventArgs = {
1573
- value: item ? fieldValue : null,
1574
- itemData: { text: currentText, value: currentValue },
1575
- item: this.getDataByValue(this.value),
1576
- previousItemData: prevItemData,
1577
- previousItemElement: prevItemEle,
1578
- itemElement: this.inputWrapper,
1579
- event: null,
1580
- isInteracted: !isRerender
1581
- };
1582
- this.updateValues(currentValue, currentText, currentIndex, ChangeEventArgs, isInitial);
1583
- }
1584
-
1585
- private updateCurrentValues(item: { [key: string]: Object }, dataList: { [key: string]: Object }[]): { currentValue: string | null,
1586
- currentText: string | null, currentIndex: number } {
1587
- if (!isNOU(item)) {
1588
- const fieldText: string = this.updateFieldValue(this.fields.text, item);
1589
- const fieldValue: string = this.updateFieldValue(this.fields.value, item);
1590
- Input.setValue(fieldText, this.inputEle, this.floatLabelType, this.showClearButton);
1591
- return {
1592
- currentValue: fieldValue,
1593
- currentText: fieldText,
1594
- currentIndex: dataList.indexOf(item)
1595
- };
1596
- }
1597
- return {
1598
- currentValue: null,
1599
- currentText: null,
1600
- currentIndex: null
1601
- };
1602
- }
1603
-
1604
- private renderPopup(): void {
1605
- this.popupEle = this.createElement('div', {
1606
- id: this.element.id + '_options', className: MULTICOLUMNLIST + ' e-popup ' + (this.cssClass !== null ? this.cssClass : '')
1607
- });
1608
- attributes(this.popupEle, { 'aria-label': this.element.id, 'role': 'dialog' });
1609
- document.body.appendChild(this.popupEle);
1610
- this.createPopup(this.popupEle);
1611
- prepend([this.popupDiv], this.popupEle);
1612
- if (this.footerTemplate) { this.setFooterTemplate(); }
1613
- let popupHeight: string = this.getSize(false);
1614
- this.popupEle.style.maxHeight = popupHeight;
1615
- if (this.footerTemplate) {
1616
- const height: number = Math.round(this.footer.getBoundingClientRect().height);
1617
- popupHeight = formatUnit(parseInt(popupHeight, 10) - height + 'px');
1618
- }
1619
- this.popupDiv.style.maxHeight = popupHeight;
1620
- this.updateGridHeight();
1621
- this.popupEle.style.visibility = 'hidden';
1622
- this.isInitialRender = true;
1623
- }
1624
-
1625
- private updateGridHeight(isFilter?: boolean, autoHeight?: boolean): void {
1626
- let height: string;
1627
- if (isFilter) {
1628
- const gridContentEle: HTMLElement = this.gridObj.getContent().querySelector('.e-content');
1629
- const scrollBarHeight: number = gridContentEle.offsetHeight - gridContentEle.clientHeight;
1630
- if (this.fields.groupBy !== '' && !isNOU(this.fields.groupBy)) { this.popupRowHeight += this.popupRowHeight; }
1631
- height = autoHeight ? (this.popupRowHeight < this.prevGridHeight ? (this.popupRowHeight + scrollBarHeight) + 'px' : this.prevGridHeight + 'px') : this.prevGridHeight + 'px';
1632
- }
1633
- else {
1634
- this.prevGridHeight = this.popupDiv.getBoundingClientRect().height - this.popupDiv.querySelector('.e-gridheader').getBoundingClientRect().height;
1635
- height = this.prevGridHeight + 'px';
1636
- }
1637
- const prevOnChange: boolean = this.isProtectedOnChange;
1638
- this.isProtectedOnChange = true;
1639
- this.gridObj.height = height;
1640
- this.isProtectedOnChange = prevOnChange;
1641
- }
1642
-
1643
- private createPopup(element: HTMLElement): void {
1644
- this.popupObj = new Popup(element, {
1645
- width: this.getSize(true),
1646
- targetType: 'relative',
1647
- collision: { X: 'flip', Y: 'flip' },
1648
- relateTo: this.inputWrapper,
1649
- enableRtl: this.enableRtl,
1650
- position: { X: 'left', Y: 'bottom' },
1651
- targetExitViewport: () => {
1652
- if (!Browser.isDevice) {
1653
- this.hidePopup();
1654
- }
1655
- },
1656
- open: () => {
1657
- this.inputEle.focus();
1658
- this.updateClearIconState();
1659
- }
1660
- });
1661
- }
1662
-
1663
- private setFooterTemplate(): void {
1664
- if (this.footer) {
1665
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1666
- if ((this as any).isReact && typeof this.footerTemplate === 'function') {
1667
- this.clearTemplate(['footerTemplate']);
1668
- } else {
1669
- this.footer.innerHTML = '';
1670
- }
1671
- } else {
1672
- this.footer = this.createElement('div');
1673
- addClass([this.footer], 'e-popup-footer');
1674
- }
1675
- const compiledString: Function = this.getTemplateFunction(this.footerTemplate);
1676
- const dataCount: number = (<{ [key: string]: Object }[]>this.dataSource).length;
1677
- let tempArr: Element[] = compiledString({ count: dataCount }, this, 'footerTemplate', this.element.id + 'footerTemplate', this.isStringTemplate, undefined, this.footer);
1678
- if (tempArr) {
1679
- tempArr = Array.prototype.slice.call(tempArr);
1680
- append(tempArr, this.footer);
1681
- }
1682
- append([this.footer], this.popupEle);
1683
- }
1684
-
1685
- private l10nUpdate(actionFailure?: boolean): void {
1686
- if (this.noRecord) {
1687
- this.noRecord.innerHTML = '';
1688
- } else {
1689
- this.noRecord = this.createElement('div');
1690
- }
1691
- if (this.noRecordsTemplate !== 'No records found' || this.actionFailureTemplate !== 'Request Failed') {
1692
- const template: string | Function = actionFailure ? this.actionFailureTemplate : this.noRecordsTemplate;
1693
- const templateId: string = actionFailure ? this.element.id + '_actionFailure' : this.element.id + '_noRecords';
1694
- const templatestring: string = actionFailure ? 'actionFailureTemplate' : 'noRecordsTemplate';
1695
- const compiledString: Function = this.getTemplateFunction(template);
1696
- let tempArr: Element[] = compiledString({}, this, templatestring, templateId, this.isStringTemplate, undefined, this.noRecord);
1697
- if (tempArr) {
1698
- tempArr = Array.prototype.slice.call(tempArr);
1699
- append(tempArr, this.noRecord);
1700
- }
1701
- } else {
1702
- const l10nLocale: Object = { noRecordsTemplate: 'No records found', actionFailureTemplate: 'Request Failed' };
1703
- this.l10n = new L10n('multicolumncombobox', l10nLocale, this.locale);
1704
- this.noRecord.innerHTML = actionFailure ?
1705
- this.l10n.getConstant('actionFailureTemplate') : this.l10n.getConstant('noRecordsTemplate');
1706
- }
1707
- addClass([this.noRecord], 'e-no-records');
1708
- prepend([this.noRecord], this.popupDiv);
1709
- this.popupObj.refreshPosition();
1710
- }
1711
-
1712
- /**
1713
- * Gets template content based on the template property value.
1714
- *
1715
- * @param {string | Function} template - Template property value.
1716
- * @returns {Function} - Return template function.
1717
- * @hidden
1718
- */
1719
- private getTemplateFunction(template: string | Function): Function {
1720
- if (typeof template === 'string') {
1721
- let content: string = '';
1722
- try {
1723
- const tempEle: HTMLElement = select(template);
1724
- if (tempEle) {
1725
- //Return innerHTML incase of jsrenderer script else outerHTML
1726
- content = tempEle.tagName === 'SCRIPT' ? tempEle.innerHTML : tempEle.outerHTML;
1727
- } else {
1728
- content = template;
1729
- }
1730
- } catch (e) {
1731
- content = template;
1732
- }
1733
- return compile(content);
1734
- } else {
1735
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
1736
- return compile(template as any);
1737
- }
1738
- }
1739
-
1740
- /*To calculate the width and height of the popup */
1741
- private getSize(ispopupWidth: boolean): string {
1742
- const currentDimension: string | number = ispopupWidth ? this.popupWidth : this.popupHeight;
1743
- let size: string = formatUnit(currentDimension);
1744
- if (size.includes('%')) {
1745
- const dimensionValue: number = ispopupWidth ? this.inputWrapper.offsetWidth : document.documentElement.clientHeight;
1746
- size = (dimensionValue * parseFloat(size) / 100).toString() + 'px';
1747
- } else if (typeof currentDimension === 'string') {
1748
- size = currentDimension.match(/px|em/) ? currentDimension : size;
1749
- }
1750
- return size;
1751
- }
1752
-
1753
- private selectedGridRow(row: Element, e?: MouseEvent | KeyboardEvent | TouchEvent, isKeyNav?: boolean): void {
1754
- const eventArgs: SelectEventArgs = {
1755
- isInteracted: e ? true : false,
1756
- item: this.gridObj.getSelectedRecords()[0],
1757
- itemElement: row as HTMLElement,
1758
- itemData: this.gridObj.getSelectedRecords()[0] as { text: string, value: string },
1759
- event: e,
1760
- cancel: false
1761
- };
1762
- const selectedRecords: { [key: string]: Object } = this.gridObj.getSelectedRecords()[0] as { [key: string]: Object };
1763
- const dataText: string = selectedRecords ? this.updateFieldValue(this.fields.text, selectedRecords) : '';
1764
- const dataValue: string = selectedRecords ? this.updateFieldValue(this.fields.value, selectedRecords) : '';
1765
- const ChangeEventArgs: ChangeEventArgs = {
1766
- isInteracted: e ? true : false,
1767
- item: selectedRecords,
1768
- itemElement: row as HTMLElement,
1769
- itemData: { text: selectedRecords ? dataText : '', value: selectedRecords ? dataValue : '' },
1770
- event: e,
1771
- cancel: false,
1772
- value: selectedRecords ? dataValue : '',
1773
- previousItemData: { text: this.text, value: this.value },
1774
- previousItemElement: this.previousItemElement
1775
- };
1776
- this.trigger('select', eventArgs, (eventArgs: SelectEventArgs) => {
1777
- if (!eventArgs.cancel && eventArgs.itemData) {
1778
- const event: KeyboardEvent = e as KeyboardEvent;
1779
- const isUpdateVal: boolean = event.key === 'Enter' || event.key === 'Tab' || event.shiftKey && event.key === 'Tab' || event.altKey && event.key === 'ArrowUp';
1780
- if (!isKeyNav || (isKeyNav && isUpdateVal)) {
1781
- this.updateValues(selectedRecords ? dataValue : '', selectedRecords ? dataText : '', this.gridObj.selectedRowIndex, ChangeEventArgs);
1782
- }
1783
- Input.setValue(selectedRecords ? dataText : '', this.inputEle, this.floatLabelType, this.showClearButton);
1784
- this.setHiddenValue();
1785
- if (!isKeyNav || (isKeyNav && isUpdateVal)) { this.hidePopup(e as KeyboardEventArgs); }
1786
- }
1787
- });
1788
- }
1789
-
1790
- private updateValues(value: string, text: string, index: number, eventArgs: ChangeEventArgs, isInitial?: boolean): void {
1791
- this.previousItemElement = eventArgs.itemElement;
1792
- const prevOnChange: boolean = this.isProtectedOnChange;
1793
- this.isProtectedOnChange = true;
1794
- this.text = text || this.text;
1795
- this.value = value || this.value;
1796
- this.index = this.selectedRowIndex = !isNOU(index) ? index : this.index;
1797
- this.isProtectedOnChange = prevOnChange;
1798
- this.setHiddenValue();
1799
- if (!isInitial) { this.triggerChangeEvent(eventArgs); }
1800
- }
1801
-
1802
- private triggerChangeEvent(eventArgs: ChangeEventArgs): void {
1803
- this.trigger('change', eventArgs, (eventArgs: ChangeEventArgs) => {
1804
- if (eventArgs.cancel) {
1805
- return;
1806
- }
1807
- });
1808
- }
1809
-
1810
- private inputHandler(e: Event): void {
1811
- this.showPopup(null, true);
1812
- this.updateClearIconState();
1813
- if (this.allowFiltering) {
1814
- this.typedString = (<HTMLInputElement>e.target).value.toLowerCase();
1815
- const eventArgs: FilteringEventArgs = {
1816
- preventDefaultAction: false,
1817
- text: this.typedString,
1818
- updateData: (
1819
- dataSource: { [key: string]: Object }[] | DataManager,
1820
- query?: Query,
1821
- fields?: FieldSettingsModel) => {
1822
- if (eventArgs.cancel) { return; }
1823
- this.isCustomFilter = true;
1824
- this.customFilterQuery = query ? query.clone() : query;
1825
- this.setGridData(dataSource, query);
1826
- },
1827
- event: e,
1828
- cancel: false
1829
- };
1830
- this.trigger('filtering', eventArgs, (eventArgs: FilteringEventArgs) => {
1831
- if (!eventArgs.cancel && !eventArgs.preventDefaultAction && !this.isCustomFilter) {
1832
- this.setGridData(this.dataSource, this.query ? this.query.clone() : null);
1833
- }
1834
- });
1835
- }
1836
- this.updateInputValue((<HTMLInputElement>e.target).value);
1837
- }
1838
-
1839
- private async updateInputValue(inputValue: string): Promise<void> {
1840
- let data: { [key: string]: Object }[];
1841
- let exactData: { [key: string]: Object }[];
1842
- if (this.dataSource instanceof DataManager) {
1843
- ({ data, exactData } = this.filterDatas(this.mainData as { [key: string]: Object }[], inputValue));
1844
- } else if (Array.isArray(this.dataSource)) {
1845
- ({ data, exactData } = this.filterDatas(this.dataSource, inputValue));
1846
- }
1847
- this.selectFilteredRows(data, exactData);
1848
- }
1849
-
1850
- private filterDatas(dataSource: { [key: string]: Object }[], inputValue: string): { data: { [key: string]: Object }[],
1851
- exactData: { [key: string]: Object }[] } {
1852
- const data: { [key: string]: Object }[] = dataSource.filter((item: { [key: string]: Object }) => {
1853
- const fieldText: string = this.updateFieldValue(this.fields.text, item);
1854
- return inputValue && fieldText.toLowerCase().startsWith(inputValue.toLowerCase());
1855
- });
1856
- const exactData: { [key: string]: Object }[] = dataSource.filter((item: { [key: string]: Object }) => {
1857
- const fieldText: string = this.updateFieldValue(this.fields.text, item);
1858
- return fieldText === inputValue;
1859
- });
1860
- return { data, exactData };
1861
- }
1862
-
1863
- private selectFilteredRows(data: { [key: string]: Object }[], exactData: { [key: string]: Object }[]): void {
1864
- if (data.length <= 0) {
1865
- this.matchedRowEle = this.matchedContent = this.exactMatchedContent = null;
1866
- return;
1867
- }
1868
- this.matchedContent = data[0];
1869
- this.exactMatchedContent = exactData[0];
1870
- const selectedIndex: number = this.findIndex(this.gridObj.currentViewData, this.matchedContent);
1871
- this.matchedRowEle = this.gridObj.getRowByIndex(selectedIndex);
1872
- }
1873
-
1874
- private updateGridDataSource(): void {
1875
- if (this.gridData && (this.gridData as any).length > 0) {
1876
- removeClass([this.popupDiv], [NODATA]);
1877
- const noRecordEle: HTMLElement = this.popupDiv.querySelector('.e-no-records');
1878
- if (noRecordEle) { this.popupDiv.removeChild(noRecordEle); }
1879
- this.gridObj.dataSource = this.gridData;
1880
- this.isDataFiltered = true;
1881
- } else {
1882
- this.l10nUpdate();
1883
- addClass([this.popupDiv], [NODATA]);
1884
- }
1885
- }
1886
-
1887
- private wireEvents(): void {
1888
- if (!isNOU(this.inputObj.buttons[0])) {
1889
- EventHandler.add(this.inputObj.buttons[0], 'mousedown', this.preventBlur, this);
1890
- EventHandler.add(this.inputObj.buttons[0], 'mousedown', this.dropDownClick, this);
1891
- }
1892
- EventHandler.add(document, 'mousedown', this.onDocumentClick, this);
1893
- EventHandler.add(this.gridEle, 'click', this.onMouseClick, this);
1894
- EventHandler.add(this.inputEle, 'input', this.inputHandler, this);
1895
- EventHandler.add(this.inputEle, 'focus', this.focusIn, this);
1896
- if (this.showClearButton) {
1897
- EventHandler.add(this.inputObj.clearButton, 'mousedown', this.clearText, this);
1898
- }
1899
- EventHandler.add(<HTMLElement & Window><unknown>window, 'resize', this.windowResize, this);
1900
- this.keyboardModule = new KeyboardEvents(
1901
- this.inputWrapper,
1902
- {
1903
- keyAction: this.keyActionHandler.bind(this),
1904
- keyConfigs: this.keyConfigs,
1905
- eventName: 'keydown'
1906
- }
1907
- );
1908
- this.keyboardModule = new KeyboardEvents(
1909
- this.gridEle,
1910
- {
1911
- keyAction: this.gridKeyActionHandler.bind(this),
1912
- keyConfigs: this.keyConfigs,
1913
- eventName: 'keydown'
1914
- }
1915
- );
1916
- }
1917
-
1918
- private unWireEvents(): void {
1919
- if (!isNOU(this.inputObj.buttons[0])) {
1920
- EventHandler.remove(this.inputObj.buttons[0], 'mousedown', this.preventBlur);
1921
- EventHandler.remove(this.inputObj.buttons[0], 'mousedown', this.dropDownClick);
1922
- }
1923
- EventHandler.remove(document, 'mousedown', this.onDocumentClick);
1924
- EventHandler.remove(this.inputEle, 'input', this.inputHandler);
1925
- EventHandler.remove(this.inputWrapper, 'focus', this.focusIn);
1926
- EventHandler.remove(<HTMLElement & Window><unknown>window, 'resize', this.windowResize);
1927
- EventHandler.remove(this.gridEle, 'click', this.onMouseClick);
1928
- if (this.showClearButton) {
1929
- EventHandler.remove(this.inputObj.clearButton, 'mousedown', this.clearText);
1930
- }
1931
- if (this.keyboardModule) { this.keyboardModule.destroy(); }
1932
- }
1933
-
1934
- private preventBlur(e: MouseEvent): void {
1935
- e.preventDefault();
1936
- }
1937
-
1938
- private dropDownClick(e: MouseEvent): void {
1939
- if (this.disabled || this.readonly) { return; }
1940
- const focusedEle: HTMLElement = this.gridEle.querySelector('.e-row-focus');
1941
- if (focusedEle) { focusedEle.classList.remove('e-row-focus'); }
1942
- if (this.isPopupOpen) { this.hidePopup(e); }
1943
- else { this.showPopup(e); }
1944
- }
1945
-
1946
- private onMouseClick(e: MouseEvent): void {
1947
- const target: Element = <Element>e.target;
1948
- const row: HTMLElement = <HTMLElement>closest(target, '.e-row');
1949
- const selectedRowIndex: number = this.gridObj.selectedRowIndex;
1950
- if (row) {
1951
- if (selectedRowIndex >= 0) { this.selectedGridRow(row, e); }
1952
- else {
1953
- this.gridObj.selectedRowIndex = this.gridObj.getRows().indexOf(row);
1954
- this.gridObj.selectRow(this.gridObj.selectedRowIndex);
1955
- this.hidePopup(e);
1956
- }
1957
- }
1958
- }
1959
-
1960
- private onDocumentClick(e: MouseEvent): void {
1961
- const target: HTMLElement = e.target as HTMLElement;
1962
- if (this.disabled || this.readonly || !this.isPopupOpen) {
1963
- if (!target.closest('.e-multicolumn-list')) { this.focusOut(); }
1964
- return;
1965
- }
1966
- if ((target.classList.contains('e-multicolumn-list-icon') || closest(target, '.e-multicolumn-list.e-popup'))) { e.preventDefault(); }
1967
- else {
1968
- if (!target.classList.contains('e-multicolumncombobox') && !target.classList.contains('e-clear-icon')) {
1969
- if (!isNOU(this.text)) { this.updateInputValue(this.text); }
1970
- const isClearVal: boolean = this.inputEle.value === '' ? true : false;
1971
- this.updateValuesOnInput(e, null, isClearVal);
1972
- }
1973
- }
1974
- }
1975
-
1976
- private updateValuesOnInput(mouseEvent?: MouseEvent, keyEvent?: KeyboardEventArgs, isClearValues?: boolean,
1977
- isKeyDown: boolean = false): void {
1978
- const e: MouseEvent | KeyboardEventArgs = mouseEvent ? mouseEvent : keyEvent;
1979
- const val: { [key: string]: Object } = isKeyDown ? this.matchedContent : this.exactMatchedContent;
1980
- if (!val && (e as KeyboardEventArgs).code !== 'Enter') { this.inputEle.value = this.value = this.index = this.text = null; }
1981
- this.hidePopup(e);
1982
- if (this.matchedRowEle && !isClearValues && val) {
1983
- const prevOnChange: boolean = this.isProtectedOnChange;
1984
- this.isProtectedOnChange = true;
1985
- const fieldText: string = this.updateFieldValue(this.fields.text, this.matchedContent);
1986
- const fieldValue: string = this.updateFieldValue(this.fields.value, this.matchedContent);
1987
- this.inputEle.value = fieldText;
1988
- this.value = fieldValue;
1989
- const selectIndex: number = this.findIndex(this.gridObj.currentViewData, this.matchedContent);
1990
- this.index = selectIndex;
1991
- this.text = fieldText;
1992
- this.gridObj.selectRow(selectIndex);
1993
- this.selectedGridRow(this.gridObj.getRowByIndex(selectIndex), e);
1994
- this.previousItemElement = this.gridObj.getSelectedRows()[0] as HTMLElement;
1995
- this.isProtectedOnChange = prevOnChange;
1996
- }
1997
- else {
1998
- if (this.isDataFiltered) {
1999
- this.inputEle.value = '';
2000
- const ChangeEventArgs: ChangeEventArgs = {
2001
- value: null,
2002
- itemData: { text: null, value: null },
2003
- item: null,
2004
- previousItemData: { text: this.text, value: this.value },
2005
- previousItemElement: this.previousItemElement,
2006
- itemElement: null,
2007
- event: e,
2008
- isInteracted: true,
2009
- cancel: false
2010
- };
2011
- const prevOnChange: boolean = this.isProtectedOnChange;
2012
- this.isProtectedOnChange = true;
2013
- this.text = this.value = this.index = null;
2014
- this.gridObj.refreshColumns();
2015
- this.isProtectedOnChange = prevOnChange;
2016
- this.triggerChangeEvent(ChangeEventArgs);
2017
- this.isDataFiltered = false;
2018
- this.matchedContent = this.matchedRowEle = null;
2019
- }
2020
- }
2021
- }
2022
-
2023
- private clearText(e: MouseEvent): void {
2024
- this.isDataFiltered = true;
2025
- this.updateValuesOnInput(e, null, true);
2026
- }
2027
-
2028
- private windowResize(): void {
2029
- if (this.popupObj) {
2030
- this.popupObj.setProperties({ width: this.getSize(true) });
2031
- this.popupObj.refreshPosition();
2032
- }
2033
- }
2034
-
2035
- /* To set cssclass for the dropdowntree */
2036
- private setCssClass(newClass: string, oldClass: string): void {
2037
- const elements: HTMLElement[] = this.popupObj ? [this.inputWrapper, this.popupObj.element] : [this.inputWrapper];
2038
- if (!isNOU(oldClass) && oldClass !== '') {
2039
- removeClass(elements, oldClass.split(' '));
2040
- }
2041
- if (!isNOU(newClass) && newClass !== '') {
2042
- addClass(elements, newClass.split(' '));
2043
- }
2044
- }
2045
-
2046
- private keyActionHandler(e: KeyboardEventArgs): void {
2047
- switch (e.action) {
2048
- case 'escape':
2049
- case 'altUp':
2050
- case 'shiftTab':
2051
- case 'tab':
2052
- if (this.isPopupOpen) { this.hidePopup(e); }
2053
- else { this.focusOut(); }
2054
- break;
2055
- case 'altDown':
2056
- if (!this.isPopupOpen) {
2057
- this.showPopup(e);
2058
- this.updateSelectedItem(e, false);
2059
- }
2060
- break;
2061
- case 'moveDown':
2062
- case 'moveUp':
2063
- this.updateSelectedItem(e, true, true);
2064
- break;
2065
- case 'enter':
2066
- this.updateValuesOnInput(null, e, false, true);
2067
- this.focusIn(e);
2068
- break;
2069
- case 'home':
2070
- case 'end':
2071
- this.updateSelectedItem(e);
2072
- break;
2073
- }
2074
- }
2075
-
2076
- private gridKeyActionHandler(e: KeyboardEventArgs, isGroup?: boolean): void {
2077
- const keyActionMap: { [key: string]: string } = {
2078
- 'ArrowDown': 'moveDown',
2079
- 'ArrowUp': 'moveUp',
2080
- 'End': 'end',
2081
- 'Home': 'home',
2082
- 'Tab': 'tab',
2083
- 'Escape': 'escape',
2084
- 'Shift+Tab': 'shiftTab',
2085
- 'Alt+ArrowUp': 'altUp'
2086
- };
2087
- if (isGroup) {
2088
- const key: string = `${e.altKey ? 'Alt+' : ''}${e.shiftKey ? 'Shift+' : ''}${e.key}`;
2089
- e.action = keyActionMap[key as string] || e.action;
2090
- }
2091
- switch (e.action) {
2092
- case 'escape':
2093
- case 'tab':
2094
- case 'shiftTab':
2095
- case 'altUp':
2096
- if (this.isPopupOpen) {
2097
- e.preventDefault();
2098
- if (e.action !== 'escape') {
2099
- this.updateSelectedItem(e);
2100
- }
2101
- this.hidePopup(e);
2102
- }
2103
- break;
2104
- case 'moveDown':
2105
- case 'moveUp':
2106
- case 'home':
2107
- case 'end':
2108
- this.updateSelectedItem(e);
2109
- break;
2110
- }
2111
- }
2112
-
2113
- private updateSelectedItem(e: KeyboardEventArgs, isUpdateIndex: boolean = true, isInputTarget?: boolean): void {
2114
- if (this.isPopupOpen) {
2115
- let index: number = this.fields.groupBy ? (this.gridObj.selectedRowIndex || 0) : this.gridObj.selectedRowIndex;
2116
- const dataLength: number = this.dataSource instanceof DataManager ? this.remoteDataLength :
2117
- (this.dataSource as { [key: string]: Object }[]).length;
2118
- if ((index === -1 && (e.action === 'moveDown' || e.action === 'moveUp')) || (e.action === 'home')) { index = 0; }
2119
- else if ((index >= (dataLength - 1) && e.action === 'moveDown') || (e.action === 'end')) { index = dataLength - 1; }
2120
- else if (e.action === 'moveDown' && (index >= 0 && index <= (dataLength - 1)) && (this.fields.groupBy || isInputTarget)) { index += 1; }
2121
- else if (e.action === 'moveUp' && index > 0 && (this.fields.groupBy) || isInputTarget) { index -= 1; }
2122
- if (!this.enableVirtualization) { this.selectRow(e, isUpdateIndex, index); }
2123
- else { setTimeout((): void => { this.selectRow(e, isUpdateIndex, index); }); }
2124
- }
2125
- }
2126
-
2127
- private selectRow(e: KeyboardEventArgs, isUpdateIndex: boolean = true, index: number): void {
2128
- this.gridObj.selectRow(index);
2129
- this.gridObj.selectedRowIndex = index;
2130
- const focusedEle: HTMLElement = this.gridEle.querySelector('.e-row-focus');
2131
- if (focusedEle) { focusedEle.classList.remove('e-row-focus'); }
2132
- if (isUpdateIndex) { this.selectedGridRow(this.gridObj.getRows()[parseInt(index.toString(), 10)], e, true); }
2133
- }
2134
-
2135
- private updateClearIconState(): void {
2136
- const clearIconEle: HTMLElement = this.inputWrapper.querySelector('.e-clear-icon');
2137
- if (clearIconEle) { clearIconEle.style.display = this.inputEle.value === '' ? 'none' : 'flex'; }
2138
- }
2139
-
2140
- private updateDynamicDataSource(newDataSource: Object | DataManager | DataResult,
2141
- oldDataSource: Object | DataManager | DataResult): void {
2142
- if (this.gridObj) {
2143
- let dataLength: number;
2144
- this.isShowSpinner = true;
2145
- this.setGridData(newDataSource);
2146
- const isRemoteData: boolean = oldDataSource instanceof DataManager;
2147
- if (isRemoteData) {
2148
- (oldDataSource as DataManager).executeQuery(new Query()).then((e: Object) => {
2149
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2150
- dataLength = (e as any).result.length;
2151
- });
2152
- } else {
2153
- dataLength = (oldDataSource as { [key: string]: Object }[]).length;
2154
- }
2155
- if (dataLength === 0) { this.popupDiv.appendChild(this.gridEle); }
2156
- }
2157
- }
2158
-
2159
- /**
2160
- * Sets the focus to the component for interaction.component for interaction.
2161
- *
2162
- * @param {FocusEvent | MouseEvent | KeyboardEvent | TouchEvent} e - Specifies the event.
2163
- * @returns {void}
2164
- */
2165
- public focusIn(e?: FocusEvent | MouseEvent | KeyboardEvent | TouchEvent): void {
2166
- if (this.disabled || this.readonly) { return; }
2167
- addClass([this.inputWrapper], [INPUTFOCUS]);
2168
- this.inputEle.focus();
2169
- this.updateClearIconState();
2170
- this.trigger('focus', e);
2171
- if (this.floatLabelType !== 'Never') {
2172
- Input.calculateWidth(this.inputEle, this.inputWrapper);
2173
- }
2174
- }
2175
-
2176
- /**
2177
- * Moves the focus from the component if the component is already focused.
2178
- *
2179
- * @param {MouseEvent | KeyboardEvent} e - Specifies the event.
2180
- * @returns {void}
2181
- */
2182
- public focusOut(e?: MouseEvent | KeyboardEventArgs): void {
2183
- if (this.disabled || this.readonly) { return; }
2184
- if (this.isPopupOpen) { this.hidePopup(e); }
2185
- if (this.inputWrapper) {
2186
- removeClass([this.inputWrapper], [INPUTFOCUS]);
2187
- const clearIconEle: HTMLElement = this.inputWrapper.querySelector('.e-clear-icon');
2188
- if (clearIconEle) { clearIconEle.style.display = 'none'; }
2189
- if (this.floatLabelType !== 'Never') {
2190
- Input.calculateWidth(this.inputEle, this.inputWrapper);
2191
- }
2192
- }
2193
- }
2194
-
2195
- /**
2196
- * Opens the popup that displays the list of items.
2197
- *
2198
- * @param {MouseEvent | KeyboardEventArgs | TouchEvent} e - Specifies the event.
2199
- * @param {boolean} isInputOpen - Specifies whether the input is open or not.
2200
- * @returns {void}
2201
- */
2202
- public showPopup(e?: MouseEvent | KeyboardEventArgs | TouchEvent, isInputOpen?: boolean): void {
2203
- const animModel: AnimationModel = { name: 'FadeIn', duration: 100 };
2204
- const eventArgs: PopupEventArgs = { popup: this.popupObj, event: e, cancel: false, animation: animModel };
2205
- this.trigger('open', eventArgs, (eventArgs: PopupEventArgs) => {
2206
- if (!eventArgs.cancel && !this.isPopupOpen) {
2207
- this.isPopupOpen = true;
2208
- this.popupObj.refreshPosition();
2209
- addClass([this.inputWrapper], [ICONANIMATION]);
2210
- attributes(this.inputEle, { 'aria-expanded': 'true', 'aria-owns': this.element.id + '_popup', 'aria-controls': this.element.id });
2211
- if (!isInputOpen) {
2212
- if ((this.value || this.text || this.index)) {
2213
- this.gridObj.selectRow(this.selectedRowIndex);
2214
- }
2215
- }
2216
- const contentEle: Element = this.gridObj.getContent();
2217
- if (contentEle) {
2218
- const activeRow: HTMLElement = contentEle.querySelector('.e-rowcell.e-active');
2219
- const firstRow: HTMLElement | null = contentEle.querySelector('.e-row');
2220
- if (activeRow) { this.inputEle.setAttribute('aria-activedescendant', activeRow.parentElement.getAttribute('data-uid')); }
2221
- else if (firstRow) { this.inputEle.setAttribute('aria-activedescendant', firstRow.getAttribute('data-uid')); }
2222
- }
2223
- if (!isNOU(this.dataSource) && this.dataSource instanceof DataManager) {
2224
- (this.dataSource as DataManager).executeQuery(new Query).then((e: Object) => {
2225
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2226
- this.remoteDataLength = (e as any).result.length;
2227
- });
2228
- }
2229
- this.popupObj.show(new Animation(eventArgs.animation), this.popupEle.firstElementChild as HTMLElement);
2230
- }
2231
- });
2232
- }
2233
-
2234
- /**
2235
- * Hides the popup if it is in open state.
2236
- *
2237
- * @param {MouseEvent | KeyboardEventArgs | TouchEvent} e - Specifies the event.
2238
- * @returns {void}
2239
- */
2240
- public hidePopup(e?: MouseEvent | KeyboardEventArgs | TouchEvent): void {
2241
- const animModel: AnimationModel = { name: 'FadeOut', duration: 100 };
2242
- const eventArgs: PopupEventArgs = { popup: this.popupObj, event: e || null, cancel: false, animation: animModel };
2243
- const target: HTMLElement | null = e ? e.target as HTMLElement : null;
2244
- this.trigger('close', eventArgs, (eventArgs: PopupEventArgs) => {
2245
- if (!eventArgs.cancel) {
2246
- this.isPopupOpen = false;
2247
- removeClass([this.inputWrapper], [ICONANIMATION]);
2248
- attributes(this.inputEle, { 'aria-expanded': 'false' });
2249
- this.popupObj.hide(new Animation(eventArgs.animation));
2250
- if (target && (target.classList.contains('e-multicolumn-list-icon') || target.classList.contains('e-rowcell'))) {
2251
- if (!this.value) { this.gridObj.refreshColumns(); }
2252
- setTimeout((): void => { this.focusIn(e); });
2253
- }
2254
- else { this.focusOut(); }
2255
- this.inputEle.removeAttribute('aria-owns');
2256
- this.inputEle.removeAttribute('aria-activedescendant');
2257
- this.customFilterQuery = null;
2258
- }
2259
- });
2260
- setTimeout((): void => {
2261
- if (this.gridObj) {
2262
- this.gridObj.dataSource = this.allowFiltering ? this.mainData : this.gridData;
2263
- const noRecordEle: HTMLElement = this.popupDiv.querySelector('.e-no-records');
2264
- if (noRecordEle) {
2265
- this.popupDiv.removeChild(noRecordEle);
2266
- removeClass([this.popupDiv], [NODATA]);
2267
- }
2268
- this.updateGridHeight(true, false);
2269
- }
2270
- }, 100);
2271
- }
2272
-
2273
- /**
2274
- * Adds a new item to the popup list. By default, new item appends to the list as the last item,
2275
- * but you can insert based on the index parameter.
2276
- *
2277
- * @param { Object[] } items - Specifies an array of JSON data or a JSON data.
2278
- * @param { number } index - Specifies the index to place the newly added item in the popup list.
2279
- * @returns {void}
2280
- */
2281
- public addItems(items: { [key: string]: Object }[] | { [key: string]: Object }, index?: number): void {
2282
- const prevOnChange: boolean = this.isProtectedOnChange;
2283
- this.isProtectedOnChange = true;
2284
- this.gridObj.editSettings.allowAdding = true;
2285
- this.gridObj.dataBind();
2286
- this.isProtectedOnChange = prevOnChange;
2287
- this.gridObj.addRecord(items, index);
2288
- }
2289
-
2290
- /* eslint-disable valid-jsdoc, jsdoc/require-returns-description */
2291
- /**
2292
- * Gets all the list items bound on this component.
2293
- *
2294
- * @returns {Element[]}
2295
- */
2296
- public getItems(): Element[] {
2297
- return this.gridObj.getDataRows();
2298
- }
2299
-
2300
- /**
2301
- * Gets the data Object that matches the given value.
2302
- *
2303
- * @param { string } value - Specifies the value of the list item.
2304
- * @returns {Object}
2305
- */
2306
- public getDataByValue(value: string): { [key: string]: Object } {
2307
- if (!isNOU(this.dataSource) && this.dataSource instanceof Array) {
2308
- return (<{ [key: string]: Object }[]>this.dataSource).filter((item: { [key: string]: Object }) => {
2309
- const fieldValue: string = this.updateFieldValue(this.fields.value, item);
2310
- return fieldValue === value;
2311
- })[0];
2312
- }
2313
- else if (!isNOU(this.dataSource) && this.dataSource instanceof DataManager){
2314
- (this.dataSource as DataManager).executeQuery(new Query()).then((e: Object) => {
2315
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2316
- const dataLists: { [key: string]: Object }[] = (e as any).result;
2317
- return dataLists.filter((item: { [key: string]: Object }) => {
2318
- const fieldValue: string = this.updateFieldValue(this.fields.value, item);
2319
- return fieldValue === value;
2320
- })[0];
2321
- });
2322
- }
2323
- return null;
2324
- }
2325
-
2326
- public destroy(): void {
2327
- this.unWireEvents();
2328
- if (this.gridObj) {
2329
- this.gridObj.destroy();
2330
- detach(this.gridObj.element);
2331
- }
2332
- if (this.inputEle) {
2333
- const attrArray: string[] = ['placeholder', 'aria-expanded', 'spellcheck', 'aria-label', 'role', 'type',
2334
- 'aria-owns', 'aria-controls', 'aria-readonly', 'autocomplete', 'autocapitalize', 'spellcheck', 'aria-activedescendant'];
2335
- for (let i: number = 0; i < attrArray.length; i++) {
2336
- this.inputEle.removeAttribute(attrArray[i as number]);
2337
- }
2338
- this.inputEle.classList.remove('e-input');
2339
- Input.setValue('', this.inputEle, this.floatLabelType, this.showClearButton);
2340
- }
2341
- if (this.popupEle) {
2342
- this.popupEle.removeAttribute('aria-label');
2343
- this.popupEle.removeAttribute('role');
2344
- }
2345
- if (this.popupObj) {
2346
- this.popupObj.destroy();
2347
- detach(this.popupObj.element);
2348
- }
2349
- if (this.element.tagName !== this.getDirective()) {
2350
- this.inputWrapper.parentElement.insertBefore(this.element, this.inputWrapper);
2351
- }
2352
- if (this.inputObj) {
2353
- detach(this.inputObj.container);
2354
- this.inputObj = null;
2355
- }
2356
- Input.destroy({
2357
- element: this.inputEle,
2358
- floatLabelType: this.floatLabelType,
2359
- properties: this.properties
2360
- });
2361
- detach(this.inputWrapper);
2362
- detach(this.popupDiv);
2363
- this.inputEle = null;
2364
- this.previousItemElement = null;
2365
- this.inputWrapper.innerHTML = '';
2366
- this.inputWrapper = null;
2367
- this.popupDiv = null;
2368
- this.popupObj = null;
2369
- this.gridObj = null;
2370
- this.gridEle = null;
2371
- this.popupEle = null;
2372
- this.footer = null;
2373
- this.noRecord = null;
2374
- this.hiddenElement = null;
2375
- this.dropdownElement = null;
2376
- super.destroy();
2377
- }
2378
-
2379
- /**
2380
- * Called internally if any of the property value changed.
2381
- *
2382
- * @param {MultiColumnComboBoxModel} newProp - Specifies new properties
2383
- * @param {MultiColumnComboBoxModel} oldProp - Specifies old properties
2384
- * @returns {void}
2385
- * @private
2386
- */
2387
- public onPropertyChanged(newProp: MultiColumnComboBoxModel, oldProp?: MultiColumnComboBoxModel): void {
2388
- for (const prop of Object.keys(newProp)) {
2389
- let gridColumns: ColumnModel[];
2390
- switch (prop) {
2391
- case 'width':
2392
- case 'popupWidth':
2393
- if (prop === 'width') { this.setElementWidth(newProp.width); }
2394
- if (this.popupObj) { this.popupObj.element.style.width = this.getSize(true); }
2395
- break;
2396
- case 'popupHeight':
2397
- if (this.popupObj) {
2398
- const height: string = this.getSize(false);
2399
- this.popupObj.element.style.maxHeight = height;
2400
- this.popupDiv.style.maxHeight = height;
2401
- this.gridObj.height = height;
2402
- }
2403
- break;
2404
- case 'placeholder':
2405
- Input.setPlaceholder(newProp.placeholder, this.inputEle);
2406
- break;
2407
- case 'readonly':
2408
- Input.setReadonly(this.readonly, this.inputEle);
2409
- break;
2410
- case 'disabled':
2411
- Input.setEnabled(!this.disabled, this.inputEle);
2412
- this.setEnable();
2413
- break;
2414
- case 'cssClass':
2415
- this.setCssClass(newProp.cssClass, oldProp.cssClass);
2416
- break;
2417
- case 'floatLabelType':
2418
- Input.removeFloating(this.inputObj);
2419
- Input.addFloating(this.inputEle, this.floatLabelType, this.placeholder);
2420
- break;
2421
- case 'showClearButton':
2422
- Input.setClearButton(newProp.showClearButton, this.inputEle, this.inputObj);
2423
- break;
2424
- case 'value':
2425
- this.initValue(true, true);
2426
- break;
2427
- case 'text':
2428
- this.initValue(true, false);
2429
- break;
2430
- case 'index':
2431
- this.initValue(true);
2432
- break;
2433
- case 'sortOrder':
2434
- if (this.gridObj) {
2435
- this.gridObj.sortSettings.columns = [{
2436
- field: this.fields.text, direction: newProp.sortOrder === SortOrder.Ascending ?
2437
- SortOrder.Ascending : SortOrder.Descending }];
2438
- }
2439
- break;
2440
- case 'htmlAttributes':
2441
- this.setHTMLAttributes();
2442
- break;
2443
- case 'noRecordsTemplate':
2444
- this.l10nUpdate();
2445
- break;
2446
- case 'actionFailureTemplate':
2447
- this.l10nUpdate(true);
2448
- break;
2449
- case 'footerTemplate':
2450
- this.setFooterTemplate();
2451
- break;
2452
- case 'itemTemplate':
2453
- if (this.gridObj) { this.gridObj.rowTemplate = newProp.itemTemplate; }
2454
- break;
2455
- case 'groupTemplate':
2456
- this.groupTemplate = newProp.groupTemplate;
2457
- this.updateGroupByField();
2458
- break;
2459
- case 'enableRtl':
2460
- if (this.gridObj && this.popupObj) {
2461
- this.gridObj.enableRtl = newProp.enableRtl;
2462
- Input.setEnableRtl(newProp.enableRtl, [this.inputWrapper]);
2463
- this.popupObj.enableRtl = newProp.enableRtl;
2464
- }
2465
- break;
2466
- case 'dataSource':
2467
- this.updateDynamicDataSource(newProp.dataSource, oldProp.dataSource);
2468
- break;
2469
- case 'query':
2470
- this.isMainDataUpdated = false;
2471
- this.setGridData(this.dataSource);
2472
- break;
2473
- case 'gridSettings':
2474
- if (this.gridObj) {
2475
- this.gridObj.gridLines = newProp.gridSettings.gridLines;
2476
- this.gridObj.rowHeight = newProp.gridSettings.rowHeight;
2477
- this.gridObj.enableAltRow = newProp.gridSettings.enableAltRow;
2478
- this.gridObj.allowResizing = newProp.gridSettings.allowResizing;
2479
- if (!(isNOU(newProp.gridSettings.allowTextWrap))) {
2480
- this.gridObj.allowTextWrap = newProp.gridSettings.allowTextWrap;
2481
- }
2482
- if (!(isNOU(newProp.gridSettings.textWrapMode))) {
2483
- this.gridObj.textWrapSettings.wrapMode = newProp.gridSettings.textWrapMode as WrapMode;
2484
- }
2485
- }
2486
- break;
2487
- case 'fields':
2488
- this.fields = newProp.fields;
2489
- this.updateGroupByField();
2490
- break;
2491
- case 'filterType':
2492
- this.filterType = newProp.filterType;
2493
- break;
2494
- case 'enableVirtualization':
2495
- if (this.gridObj) { this.enableVirtualization = this.gridObj.enableVirtualization = newProp.enableVirtualization; }
2496
- break;
2497
- case 'sortType':
2498
- if (this.gridObj) {
2499
- this.sortType = newProp.sortType;
2500
- this.gridObj.allowMultiSorting = this.sortType.toString().toLowerCase() === 'multiplecolumns' && this.allowSorting;
2501
- }
2502
- break;
2503
- case 'allowFiltering':
2504
- this.allowFiltering = newProp.allowFiltering;
2505
- break;
2506
- case 'allowSorting':
2507
- if (this.gridObj) { this.allowSorting = this.gridObj.allowSorting = newProp.allowSorting; }
2508
- break;
2509
- case 'columns':
2510
- if (this.gridObj) {
2511
- gridColumns = this.getGridColumns();
2512
- this.gridObj.columns = gridColumns;
2513
- }
2514
- break;
2515
- case 'locale':
2516
- this.isLocaleChanged = true;
2517
- break;
2518
- }
2519
- }
2520
- }
2521
- }