In a form, I have an autocomplete field that can filter and check the input (must be an element of the list). It works perfectly but it is coded in Angular 7.
I have to migrate the project in Angular 15 and it doesn't work anymore : the control is ok but the filter doesn't work.
On Angular material site, the attribute [formControl] is used but when I add it to my field, the filter is ok but the control fails....
I don't find any example on the web that do the job in ANGULAR 15
html Original code
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Rôle</mat-label>
<input #autoCompleteRoleInput type="text" matInput [matAutocomplete]="role" formControlName="role">
<mat-autocomplete #role="matAutocomplete" [displayWith]="displayFnRole">
<mat-option *ngFor="let option of filteredRoles | async" [value]="option">
{{option.libelle}}
</mat-option>
</mat-autocomplete>
<mat-error *ngIf="form.controls['role'].errors?.forbiddenRoles">
Veuillez choisir un élément de la liste.
</mat-error>
</mat-form-field>
Results : Control OK :
filter fails:
If I add [formControl]="roleControl" attribute: filter OK but check fails
TS code:
export class DialogUtilisateurComponent implements OnInit, AfterViewInit {
@ViewChild('autoCompleteRoleInput', { read: MatAutocompleteTrigger} ) autoCompleteRoleInput: MatAutocompleteTrigger;
rolesList: Role[];
roleControl = new FormControl<string | Role>('');
filteredRoles: Observable<Role[]>;
Form:
createForm(user: UserInfo) {
this.form = this.formBuilder.group({
username: [user.username, Validators.required],
name: [user.name, Validators.required],
role: [user !== null && user.roleDTO !== null ? user.roleDTO : {} as Role,
[this.inputServices.forbiddenRolesValidator(this.rolesList)]],
email: [user.email, [Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$')]],
telephone: [user.telephone, Validators.required]
});
this.form.controls['role'].setValidators(this.inputServices.forbiddenRolesValidator(this.rolesList));
this.form.controls['role'].updateValueAndValidity();
this.filteredRoles = this.roleControl.valueChanges.pipe(
startWith(''),
map(value => {
const name = typeof value === 'string' ? value : value?.libelle;
return name ? this._filter(name as string) : this.rolesList.slice();
}),
);
}
Filter :
private _filter(value: string): Role[] {
const filterValue = value.toLowerCase();
console.log('filtre avec: ' + value);
this.rolesList.forEach((item) => {
console.log(item.libelle);
})
return this.rolesList.filter(option => option.libelle.toLowerCase().indexOf(filterValue) === 0);
}
Check:
forbiddenRolesValidator(rolesList: Role[]): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
// below findIndex will check if control.value is equal to one of our options or not
const index = rolesList.findIndex(role => {
return control.value !== null ? role.libelle === control.value.libelle : null;
});
return index < 0 ? {'forbiddenRoles': {value: control.value}} : null;
};
}