2
2
// tslint:disable: template-no-call-expression
3
3
import { ActiveDescendantKeyManager } from '@angular/cdk/a11y' ;
4
4
import {
5
- AfterContentInit ,
6
5
AfterViewInit ,
7
6
ChangeDetectionStrategy ,
8
7
ChangeDetectorRef ,
@@ -71,13 +70,16 @@ const DEFAULT_DEBOUNCE_DELAY = 200;
71
70
/**
72
71
* The event object that is emitted when the select value has changed
73
72
*/
74
- export class TsAutocompleteChange < T = string [ ] | string > {
73
+ export class TsAutocompleteChange < T = unknown > {
75
74
constructor (
76
75
public source : TsAutocompleteComponent ,
77
76
public value : T ,
78
77
) { }
79
78
}
80
79
80
+ export type TsAutocompleteFormatter = ( v : unknown ) => string ;
81
+ export type TsAutocompleteComparator = ( a : unknown , b : unknown ) => boolean ;
82
+
81
83
/**
82
84
* The autocomplete UI Component
83
85
*
@@ -94,6 +96,8 @@ export class TsAutocompleteChange<T = string[] | string> {
94
96
* @example
95
97
* <ts-autocomplete
96
98
* [allowMultiple]="allowMultiple"
99
+ * [displayFormatter]="formatterFunc"
100
+ * [valueComparator]="comparatorFunc"
97
101
* debounceDelay="300"
98
102
* displayWith="(v) => v.name"
99
103
* hint="Begin typing to search.."
@@ -141,7 +145,6 @@ export class TsAutocompleteChange<T = string[] | string> {
141
145
} )
142
146
export class TsAutocompleteComponent implements OnInit ,
143
147
AfterViewInit ,
144
- AfterContentInit ,
145
148
OnDestroy ,
146
149
TsFormFieldControl < string > {
147
150
@@ -155,11 +158,6 @@ export class TsAutocompleteComponent implements OnInit,
155
158
*/
156
159
public autocompleteFormControl = new FormControl ( [ ] ) ;
157
160
158
- /**
159
- * An array of selected values
160
- */
161
- public autocompleteSelections : TsOptionComponent [ ] = [ ] ;
162
-
163
161
/**
164
162
* Store a reference to the document object
165
163
*/
@@ -417,6 +415,19 @@ export class TsAutocompleteComponent implements OnInit,
417
415
@Input ( )
418
416
public name : string | undefined ;
419
417
418
+ /**
419
+ * Define the formatter for the selected items.
420
+ */
421
+ @Input ( )
422
+ public displayFormatter : TsAutocompleteFormatter = v => v as string
423
+
424
+ /**
425
+ * Define the comparator for the values of the options
426
+ */
427
+ @Input ( )
428
+ public valueComparator : TsAutocompleteComparator = ( a : unknown , b : unknown ) => a === b
429
+
430
+
420
431
/**
421
432
* Event for when the panel is closed
422
433
*/
@@ -508,7 +519,9 @@ export class TsAutocompleteComponent implements OnInit,
508
519
throw Error ( 'form control values must be an array of values' ) ;
509
520
} else if ( this . ngControl . value ) {
510
521
this . autocompleteFormControl . setValue ( this . ngControl . value ) ;
511
- this . setSelections ( ) ;
522
+ if ( ! this . allowMultiple ) {
523
+ this . searchQuery = this . displayFormatter ( this . ngControl . value [ 0 ] ) ;
524
+ }
512
525
}
513
526
514
527
// Support dynamic form control updates
@@ -520,7 +533,9 @@ export class TsAutocompleteComponent implements OnInit,
520
533
// istanbul ignore else
521
534
if ( newValue ) {
522
535
this . autocompleteFormControl . setValue ( newValue , { emitEvent : false } ) ;
523
- this . setSelections ( ) ;
536
+ if ( ! this . allowMultiple ) {
537
+ this . searchQuery = this . displayFormatter ( newValue [ 0 ] ) ;
538
+ }
524
539
}
525
540
} ) ;
526
541
}
@@ -534,7 +549,9 @@ export class TsAutocompleteComponent implements OnInit,
534
549
throw Error ( 'ngModel must be an array of values' ) ;
535
550
}
536
551
this . autocompleteFormControl . setValue ( this . ngControl . value ) ;
537
- this . setSelections ( ) ;
552
+ if ( ! this . allowMultiple ) {
553
+ this . searchQuery = this . displayFormatter ( this . ngControl . value [ 0 ] ) ;
554
+ }
538
555
}
539
556
} ) ;
540
557
}
@@ -590,13 +607,6 @@ export class TsAutocompleteComponent implements OnInit,
590
607
591
608
}
592
609
593
- public ngAfterContentInit ( ) : void {
594
- this . setSelections ( ) ;
595
- this . options . changes
596
- . pipe ( untilComponentDestroyed ( this ) )
597
- . subscribe ( ( ) => this . setSelections ( ) ) ;
598
- }
599
-
600
610
/**
601
611
* Needed for untilComponentDestroyed
602
612
*/
@@ -793,8 +803,8 @@ export class TsAutocompleteComponent implements OnInit,
793
803
* @param selection - The item to select
794
804
*/
795
805
public autocompleteSelectItem ( selection : TsAutocompletePanelSelectedEvent ) : void {
796
- const isDuplicate = this . autocompleteSelections
797
- . findIndex ( s => selection . option . value === s . value ) >= 0 ;
806
+ const isDuplicate = ( this . autocompleteFormControl . value || [ ] )
807
+ . findIndex ( o => this . valueComparator ( o , selection . option . value ) ) >= 0 ;
798
808
799
809
// istanbul ignore else
800
810
if ( isDuplicate ) {
@@ -814,17 +824,12 @@ export class TsAutocompleteComponent implements OnInit,
814
824
this . resetAutocompleteQuery ( ) ;
815
825
}
816
826
817
- // Add to the collection
818
- this . autocompleteSelections = this . autocompleteSelections . concat ( selection . option ) ;
819
-
820
827
// Update the form control
821
- this . autocompleteFormControl . setValue ( this . autocompleteSelections . map ( s => s . value ) ) ;
828
+ const options = ( this . autocompleteFormControl . value || [ ] ) . concat ( selection . option . value ) ;
829
+ this . autocompleteFormControl . setValue ( options ) ;
822
830
} else {
823
- // Update the selected value
824
- this . autocompleteSelections = [ selection . option ] ;
825
-
826
831
// Update the form control
827
- this . autocompleteFormControl . setValue ( this . autocompleteSelections . map ( s => s . value ) ) ;
832
+ this . autocompleteFormControl . setValue ( [ selection . option . value ] ) ;
828
833
829
834
// In single selection mode, set the query input to the selection so the user can see what was selected
830
835
this . inputElement . nativeElement . value = selection . option . viewValue ;
@@ -839,7 +844,7 @@ export class TsAutocompleteComponent implements OnInit,
839
844
840
845
// Notify consumers about changes
841
846
this . optionSelected . emit ( new TsAutocompleteChange ( this , selection . option . value ) ) ;
842
- this . selectionChange . emit ( new TsAutocompleteChange ( this , this . autocompleteSelections . map ( s => s . value ) ) ) ;
847
+ this . selectionChange . emit ( new TsAutocompleteChange ( this , this . autocompleteFormControl . value ) ) ;
843
848
}
844
849
845
850
@@ -848,25 +853,17 @@ export class TsAutocompleteComponent implements OnInit,
848
853
*
849
854
* @param value - The value of the item to remove
850
855
*/
851
- public autocompleteDeselectItem ( option : TsOptionComponent ) : void {
856
+ public autocompleteDeselectItem ( option : unknown ) : void {
852
857
// Find the key of the selection in the selectedOptions array
853
- const index = this . autocompleteSelections . findIndex ( s => s . value === option . value ) ;
854
- const selections = this . autocompleteSelections . slice ( ) ;
855
- // If not found
856
- if ( index < 0 ) {
857
- return ;
858
- }
859
-
860
- // Remove the selection from the selectedOptions array
861
- selections . splice ( index , 1 ) ;
862
- this . autocompleteSelections = selections ;
858
+ const options = ( this . autocompleteFormControl . value || [ ] )
859
+ . filter ( opt => ! this . valueComparator ( opt , option ) ) ;
863
860
864
861
// Update the form control
865
- this . autocompleteFormControl . setValue ( this . autocompleteSelections . map ( s => s . value ) ) ;
862
+ this . autocompleteFormControl . setValue ( options ) ;
866
863
867
864
// If the only chip was removed, re-focus the input
868
865
// istanbul ignore else
869
- if ( this . autocompleteSelections . length < 1 ) {
866
+ if ( options . length === 0 ) {
870
867
this . focus ( ) ;
871
868
}
872
869
@@ -880,8 +877,8 @@ export class TsAutocompleteComponent implements OnInit,
880
877
} ) ;
881
878
882
879
// Notify consumers about changes
883
- this . optionDeselected . emit ( new TsAutocompleteChange ( this , option . value ) ) ;
884
- this . selectionChange . emit ( new TsAutocompleteChange ( this , this . autocompleteSelections . map ( s => s . value ) ) ) ;
880
+ this . optionDeselected . emit ( new TsAutocompleteChange ( this , option ) ) ;
881
+ this . selectionChange . emit ( new TsAutocompleteChange ( this , options ) ) ;
885
882
}
886
883
887
884
@@ -894,15 +891,4 @@ export class TsAutocompleteComponent implements OnInit,
894
891
public trackByFn ( index ) : number {
895
892
return index ;
896
893
}
897
-
898
- /**
899
- * Finds the options that have been selected.
900
- */
901
- private setSelections ( ) : void {
902
- if ( this . ngControl && this . ngControl . value && this . options ) {
903
- this . autocompleteSelections = this . options . filter ( opt => this . ngControl . value . indexOf ( opt . value ) >= 0 ) ;
904
- this . changeDetectorRef . detectChanges ( ) ;
905
- }
906
- }
907
-
908
894
}
0 commit comments