In my application, I have a FormGroup containing a FormArray with populated FormControl entries. To enhance user experience, I created a service that utilizes an Observable for value changes. This service looks up similar words in a predefined "dictionary" array and returns an array of objects to populate a suggestion list below the input field.
The suggestion list displays three terms similar to the given input string. For example, if the input is 'table', the suggestions could be:
[
{distance: 1, match : 'Table'},
{distance: 3, match : 'Fabules'},
{distance: 5, match : 'Ramioles'},
]
The Levenstein algorithm calculates the distance, representing the number of changes needed to transform one word into another.
To implement the desired behavior, clicking on a suggestion should update the value in the input field and hide the suggestion list.
An important feature is that the service initiates upon focusing on each input field, providing real-time suggestions.
component.html
<form [formGroup]="myForm">
<fieldset formArrayName="parameters">
<ng-container *ngFor="let par of parameters.controls" [formGroup]="par">
<input formControlName="name" />
<ul class="filter-select">
<li *ngFor="let r of results" class="filter-select-list">
{{ r.match }}
</li>
</ul>
</ng-container>
</fieldset>
</form>
I aim to achieve this functionality without relying on external libraries like ng2-completer or material autocomplete. Additionally, using datalist poses limitations when matching strings that contain multiple dictionary words.
Moreover, HTML5 datalist has cross-browser compatibility issues.
How can I effectively implement this behavior?
RECAP:
- Each input in the array must connect to a service triggered ON FOCUS to search for relevant words in the dictionary (successfully implemented)
- The service returns an array to populate the suggestion list (completed)
- Clicking on a suggestion updates the value
- The suggestion list disappears after selection
component.html
<input [formControl]="queryField" type="text" />
service.ts
this.queryField.valueChanges
.debounceTime(200)
.distinctUntilChanged()
.subscribe( value => {
this.results = this._searchService.spell(value)
})
SECOND PART
I devised a solution utilizing an Observable triggered by input focus to populate the suggestion list.
@Component({
selector: 'my-autocomplete-input',
styleUrls: ['./app.component.css'],
template: `
<ng-content></ng-content>
<ul class="filter-select">
<li *ngFor="let r of autosuggestList" class="filter-select-list">
<div (click)="editInput(r.match)">{{ r.match }}</div>
</li>
</ul>
`
})
export class AutocompleteComponent {
@ContentChild("input") input: ElementRef;
@Input() autosuggestList;
constructor(
private _searchService: SearchService,
) {}
editInput(res) {
this.input.nativeElement.value = res;
this.autosuggestList = [];
}
ngAfterViewInit() {
Observable.fromEvent(this.input.nativeElement, 'focus')
.subscribe((data: KeyboardEvent) => {
this.autosuggestList = this._searchService.spell(this.input.nativeElement.value)
});
}
}
However, updating the form array does not occur simultaneously. The Form Control needs manual intervention to reflect changes in the input data.
Is there a way to patch/update the form from the contentChild element, specifically within the editInput function?