Reputation: 728
I want users to pick from autocomplete elements and when they even delete one character from the selected value, I want to show them an error and I also want my FormControl
to be invalid
. So far I couldn't figure it out. I'm also filtering the autocomplete values as the user types, and that as can be seen here causes the problem. The github issue seems to have resolved
status but it still is a problem.
My component.html
file:
<form class="example-form">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>User</mat-label>
<input
placeholder="Pick one"
matInput
[formControl]="myControl"
[matAutocomplete]="auto"
/>
<mat-autocomplete
autoActiveFirstOption
#auto="matAutocomplete"
[displayWith]="displayUserFn"
(optionSelected)="valueChange('UserEntity', $event)"
>
<mat-option
*ngFor="let option of filteredOptions | async"
[value]="option"
>
{{option.name}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<span
*ngIf="(myControl.touched || myControl.dirty) && (myControl.errors?.required || myControl.errors?.incorrect)"
style="color: red"
>
User must be picked.
</span>
</form>
My component.ts
file:
export class AutocompleteFilterExample implements OnInit {
myControl = new FormControl();
options = [
{
name: 'Johnny Depp',
},
{
name: 'Jennifer Anniston',
},
{
name: 'Jennifer Hernandez',
},
{
name: 'John Cena',
},
{
name: 'Jenny Something',
},
{
name: 'Angelina Jolie',
},
];
filteredOptions: Observable<any>;
ngOnInit() {
this.myControl = new FormControl('', {
validators: [Validators.required],
asyncValidators: [this.requireMatch],
});
this.filteredOptions = this.myControl.valueChanges.pipe(
startWith(''),
map((value) =>
typeof value === 'string' ? this._filter(value) : [value]
)
);
}
requireMatch = (
control: AbstractControl
): Observable<ValidationErrors | null> => {
console.log(control);
if (!control.valueChanges || control.pristine) {
return of(null);
} else {
return this.filteredOptions.pipe(
map((users) => {
if (
users.findIndex((user) => `${user.name}` === control.value) === -1
) {
console.log('incorrect !');
return { incorrect: true };
}
console.log('correct !');
return null;
})
);
}
};
private _filter(value) {
if (value === null || value === '') return [];
const loweredString = value.toLocaleLowerCase('en-US');
return this.options
.filter(
(user) =>
`${user.name}`.toLocaleLowerCase('en-US').indexOf(loweredString) !==
-1
)
.sort((a, b) => `${a.name}`.localeCompare(`${b.name}`))
.slice(0, 20);
}
}
To clarify what I need:
When I write je
and pick one value from the list:
It shouldn't show an error as there is an option with the same value of the input. But when alter the input value, I want to see an error, which I am not at the moment.
How can I achieve this?
I added these to a stackblitz project, can be seen here.
Upvotes: 0
Views: 316
Reputation: 54579
This a known bug, currently you'll have to poll the status to get what you want :
const ctrl = new FormControl();
const statusChanges$ = merge(ctrl.statusChanges, timer(0, 500)).pipe(
map(() => ctrl.status),
distinctUntilChanged()
);
Upvotes: 3