I would like to implement an auto-complete feature or at least a dropdown with filter option on the following code. ie. when the input field is empty all the options inside array object's name property can be shown, and as and when user types something the dropdown options need to be filtered based on input text. I am completely new to Angular material and came across this code sample on stackblitz .
HTML Code:
<form (ngSubmit)="onSubmit()" [formGroup]="registerForm">
<mat-form-field >
<mat-chip-list #chipList formArrayName="Tags">
<mat-chip *ngFor="let tag of tagsArr.controls; let i = index" [removable]="true" (removed)="onRemove(i, tag)" [formGroupName]="i">
{{tag.get('Text').value}}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
<!-- Use below if only having single formcontrol -->
<!-- <mat-chip *ngFor="let tag of tagsArr.controls; let i = index" [removable]="true" (removed)="onRemove(i)">
{{tag.value}}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip> -->
</mat-chip-list>
</mat-form-field>
<mat-chip-list>
<mat-chip *ngFor="let tag of tags" [selectable]="selectable" (click)="onSelect(tag)">
{{tag.Text}}
</mat-chip>
</mat-chip-list>
<button type="submit">Submit</button>
</form>
TS file:
registerForm: FormGroup;
selected = [];
tags = [{ Text: 'one' }, { Text: 'two' }];
constructor(private fb: FormBuilder) {
this.registerForm = this.fb.group({
Tags: this.fb.array([]),
});
}
get tagsArr() {
return this.registerForm.get('Tags') as FormArray;
}
onSelect(tag: any) {
this.tagsArr.push(
this.fb.group({
Text: tag.Text,
})
);
this.tags.splice(this.tags.indexOf(tag), 1);
}
onRemove(index, tag): void {
this.tagsArr.removeAt(index);
this.tags.push(tag.value);
}
onSubmit(){
console.log(this.registerForm.value)
}
}
CodePudding user response:
Here is how you could implement a chip input with autocomplete
HTML:
<form [formGroup]="myForm">
<mat-form-field>
<mat-label translate>Tags</mat-label>
<mat-chip-list #chipList>
<mat-chip *ngFor="let tag of tags" (removed)="remove(tag)" color="accent">
{{tag}}
<button matChipRemove>
<mat-icon>cancel</mat-icon>
</button>
</mat-chip>
<input placeholder="New tag ..." #tagInput
[formControl]="tagControl"
[matAutocomplete]="auto"
[matChipInputFor]="chipList"
(matChipInputTokenEnd)="add($event)"
matChipInputAddOnBlur>
</mat-chip-list>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
<mat-option *ngFor="let tag of filteredTags | async" [value]="tag">
{{tag}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
TS:
myForm: FormGroup
filteredTags: Observable<string[]>
allTags: string[] = []
tags: string[] = []
@ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement> | undefined = undefined
constructor(
private fb: FormBuilder
) {
this.myForm= this.fb.group({
tags: ['']
})
this.filteredTags = this.tagControl.valueChanges.pipe(
startWith(null),
map(tag => tag ? this.filter(tag): this.allTags.slice())
)
}
ngOnInit(): void {
this.allTags = ['concert', 'restaurant', 'pub']
}
// TAG AUTOCOMPLETE CONTROL
get tagControl(): FormControl {
return this.myForm.get('tags') as FormControl
}
remove(tag: string): void {
const index = this.tags.indexOf(tag)
if (index >= 0) {
this.tags.splice(index, 1)
}
}
add(event: MatChipInputEvent): void {
const value = (event.value || '').trim()
if (value) {
this.tags.push(value)
}
event.chipInput?.clear()
this.tagControl.setValue(null)
}
selected(event: MatAutocompleteSelectedEvent): void {
this.tags.push(event.option.viewValue)
if (this.tagInput) {
this.tagInput.nativeElement.value = ''
}
this.tagControl.setValue(null)
}
private filter(value: string): string[] {
const filterValue = value.toLowerCase()
return this.allTags.filter(tag => tag.toLowerCase().includes(filterValue))
}