Autocomplete Component - Cannot get Reactive Form with existing value work
Opened this issue ยท 14 comments
I have the following autocomplete input:
<input cAutocomplete
highlightOptionsOnSearch
allowOnlyDefinedOptions
showHints
[loading]="isPersonsLoading"
[options]="persons"
[search]="{external: true, global: true}"
[delay]="500"
(inputChange)="personsLoad($event)"
id="person"
formControlName="person"
[valid]="itemForm.controls['person'].touched ? itemForm.controls['person'].valid : undefined" />
persons is a lazy loaded list after (inputChange):
persons: AutocompleteOption[] = []`
personsLoad(input: string) {
if (!input) {
return
}
this.isPersonsLoading = true
let query = new PagedQuery()
query.filter = input
query.sort = { column: 'LastName' }
this.http.get<PagedResult<Person>>('/api/persons', { params: query.toHttpParams() }).subscribe({
next: (result) => {
this.persons = result.results.map((person) => <AutocompleteOption>{ label: `${person.lastName}, ${person.firstName}`, value: person.id })
}
}).add(() => {
this.isPersonsLoading = false
})
}
The form definition:
itemForm = new FormGroup({
person: new FormControl('', Validators.required)
}
And the important part, setting the form value initally:
this.itemForm.get('person')!.setValue(`${this.item.person?.lastName}, ${this.item.person?.firstName}`)
And now whenever I change the autocomplete input, the list of options is not displayed, but the input resets immediatly to the inital value.
If no initial value is set, the input works as expected.
On further analysis, this not only happens with Reactive Forms, but also Template-driven. As long as a value is specified before changing the input for the first time, it always resets to the initial value.
Can you have a look at the following too?
The (optionChange) is called twice during initialization.
Always once with a -null- value.
And if a ngModel is assiged, a second time with that value.
As I understand it, (optionChange) should really only be called, if the user has selected an option from the list.
@bernik1980 could you check it out with 5.5.15 ?
@xidedix I checked 5.5.15:
- The indicator problem is solved
- The reset to the initial value still happes
- (optionChange) is still called twice during initialization
I really like this control, but without beeing able to set an initial value, it cannot be used in most cases.
Please let me know, if I can assist any further.
@bernik1980, thanks for the feedback! We successfully replicated the issue of resetting to the initial value.
wip
@bernik1980 please let us know about version 5.5.16
@xidedix I checked 5.5.16
- The indicator problem is solved
- The reset problem is solved
- (optionChange) is called when assigning a string value via the formGroup (see Problem 3)
- (inputChange) is called once with empty value during init (see Problem 4)
- When disabling the control via the formGroup, this state is not reflected to the input (see Problem 5)
- Nice to have: Support for template to show instead of only strings, to allow more complex elements
Problem 3
When assigning an initial value to the control via the fromGroup, (optionChange) is called with the string value. This seems to be wrong, since no option was selected or changed. (optionChange) should only be called, if the user clicked an option from the list.
this.itemForm.get('person')!.setValue(this.item.person ? (this.item.person.lastName + ', ' + this.item.person.firstName) : null)
Problem 4
For unknown reasons, (inputChange) is called with an empty value during initialization. Although this is not a big problem at the moment, because no server request is made for an empty string, it could still be possible to show a list of "Last entries". (inputChange) should only be called, if the user actually did change the input.
Problem 5
When disabling the related control of the formGroup, the input itself is still enabled, the input can be changed and (inputChange) etc. is called. But since its disabled for the formGroup, validation will not happen. This is a big issue and needs to be fixed.
this.itemForm.get('person')!.disable()
@bernik1980, thanks again for your feedback!
The latest version, 5.5.17, should fix all the issues you mentioned.
Weโve also introduced custom templates with this release.
Please let us know if it works for you.
Thank you very much vor the update.
I can confirm, that Problem 5 is solved. And the support for a template is really great.
Problem 3 and Problem 4 still remain in an Reactive form environment.
I can handle Problem 3, because the IAutocompleteOption of the callback does only contain the label, which equals to the value assigned the formControl. So when the value is missing, I know its the "unwanted" callback. But of course I would prefere if the callback would only be fired if the user did select an option and not when a value was assigned.
But I have noe clue, why (inputChange) is called during component load. Maybe it has something to to with the external search? The only way I can handle this, is to ignore empty (inputChange) callback.
But since the big issues have been fixed, you can close this issue, if you do not want to check Problem 3 and Problem 4 any further.
Thanks again for your great work!
@bernik1980 Thanks for letting us know. We will review the issues again.
(inputChange)is called once with an empty value during init (problem 4)
should be fixed in version 5.5.20.
Let us know if it works for your use case.
@xidedix Still not working as expected. When assigning a value to the related FormControl, the following happens in that order:
- (optionChange) is called with the assigned value as label, but without a value
- (inputChange) is called with the assigned value
Both of these feel weired, since they only should be fired, if the user did actually triggered them and not because of assigning a value.
As previously said, I can handle problem 1, because i can ignore calls without a value.
Problem 2 is a bit worse though, since I cannot easily differentiate my own assignment and an actual input of the user, resulting in an unneeded server call during init of the form.
Currently I compare the value of the callback to the value currently assigned to the form. If they match, I can ignore the call. (This works, because (inputChange) is called before the value of the FormControl is updated internally, when the user did actually change the input.)
While testing all this, a new problem occured:
3. (inputChange) is called after an option was selected by the user (so first (optionChange) immedialty followed by (inputChange))
I am not sure, if this is intended. Luckily, this is catched with the special handling of problem 2 or an unneded server call would be made.
Overall, the control is harder to handle that it should be. There are to much workarrounds needed to make it work flawlessly.
And another topic has just occurred to me:
if the input is placed inside a <c-input-group>, it has no rounded corners.
Please let me know, if I should open a Issue for that.
@bernik1980 Thanks for your feedback!
- version
5.5.22should fix the(inputChange)issue