Angular material 15 - autocomplete filter not working

125 Views Asked by At

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 :

enter image description here

filter fails:

enter image description here

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;
    };
}
0

There are 0 best solutions below