Angular mat autocomplete không hoạt động trong FormArray?
Tôi đang cố gắng triển khai tính năng tự động hoàn thành mat trong FormArray. Tôi đã theo liên kết này nhưng bảng điều khiển của tôi có rất nhiều lỗi khi tôi cố gắng mở liên kết khi đặt mã này như ví dụ bên dưới:
https://stackblitz.com/edit/angular-szxkme-yfphur?file=app%2Fautocomplete-display-example.ts
create-project.ts
export class CreateProjectComponent implements OnInit {
pageNavigation: IPageNavigation = {
pageTitle: 'Project Management',
subPages: [{ label: 'Projects', link: '/projects' }],
};
createProjectForm: FormGroup;
projectTeamMemberFormArray = new FormArray([]);
filteredEmployees: Observable<IEmployee[]>;
constructor(
private formBuilder: FormBuilder,
private projectManagementService: ProjectManagementService
) { }
ngOnInit(): void {
this.buildForm();
}
buildForm(): void {
this.createProjectForm = this.formBuilder.group({
projectTeamMembers: this.projectTeamMemberFormArray
});
}
manageNameControl(index: number) {
var arrayControl = this.createProjectForm.get('projectTeamMembers') as FormArray;
this.filteredEmployees[index] = arrayControl.at(index).get('firstName').valueChanges
.pipe(
startWith<string | IEmployee>(''),
map(value => typeof value === 'string' ? value : value.firstName),
map(name => name ? this.projectManagementService.filterEmployees(name) : null)
);
}
addProjectTeamMember(teamMember?: IProjectMember): void {
this.projectTeamMemberFormArray = this.createProjectForm.get('projectTeamMembers') as FormArray;
this.projectTeamMemberFormArray.push(this.createProjectTeamMemberItem(teamMember));
this.manageNameControl(this.projectTeamMemberFormArray.length - 1);
}
createProjectTeamMemberItem(teamMember?: IProjectMember): FormGroup {
return this.formBuilder.group({
employeeId: new FormControl((teamMember && teamMember.employeeId) || null, Validators.required),
firstName: new FormControl((teamMember && teamMember.firstName) || null, Validators.required),
memberRoles: new FormControl((teamMember && teamMember.projectRoles) || null, Validators.required),
});
}
removeProjectTeamMemberItem(index: number, item: IProjectMember) {
this.projectTeamMemberFormArray = this.createProjectForm.get('projectTeamMembers') as FormArray;
this.projectTeamMemberFormArray.removeAt(index);
this.projectTeamMembers.forEach((c: IProjectMember) => {
if (c.id === item.id) c.deleted = true;
});
}
selectEmployee(employee: IEmployee): void {
this.createProjectForm.get('employeeId').setValue(employee.id);
}
employeeTypeaheadDisplayFn(employee: IEmployee): string {
if (employee) {
return `${employee.lastName} ${employee.firstName}`;
}
return '';
}
}
create-project.html
<form #f="ngForm" (ngSubmit)="submit()" novalidate [formGroup]="createProjectForm">
<section>
<div formArrayName="projectTeamMembers" class="single-item-container"
*ngFor="let t of createProjectForm.get('projectTeamMembers').controls; let j = index">
<ng-container [formGroupName]="j">
<div class="spinner" *ngIf="showLoader">
<mat-progress-spinner [color]="'primary'" diameter="100" mode="indeterminate" value="50">
</mat-progress-spinner>
</div>
<div [formGroupName]="j" *ngIf="!showLoader" fxLayout="row" fxLayoutGap="2%">
<!-- employee -->
<mat-form-field fxFlex="100%">
<input matInput formControlName='firstName' placeholder="Start typing employee first or last name."
[matAutocomplete]="auto">
<mat-error *ngIf="t.get('firstName').errors?.required">
{{ 'FIELD_REQUIRED_MESSAGE' | translate }}
</mat-error>
</mat-form-field>
<mat-autocomplete #auto="matAutocomplete" [displayWith]="employeeTypeaheadDisplayFn" (optionSelected)="selectEmployee($event.option.value.id)">
<mat-option *ngFor="let employee of filteredEmployees[j] | async" [value]="employee">
{{ employee.firstName }} {{ employee.lastName }}
</mat-option>
</mat-autocomplete>
<div class="input-bottom">
<button mat-raised-button color="warn" (click)="removeProjectTeamMemberItem(j, t.value)">
Delete
</button>
</div>
</div>
</ng-container>
</div>
<div class="form-footer">
<div class="items-buttons">
<button mat-raised-button color="primary" type="button"
(click)="addProjectTeamMember()">{{'COMPONENTS.PROJECT.ADD_NEW_TEAM_MEMBER' | translate}}</button>
</div>
</div>
</section>
</form>
project-management.service.ts
export interface IEmployee {
id: number;
firstName: string;
lastName: string;
}
filterEmployees(searchTerm: string): Observable<IEmployee[]> {
const reqUrl = `${environment.mPortalWebApi}employee-profiles/search?searchTerm=${searchTerm}`;
return this.http.get(reqUrl).pipe(
map((response: IEmployee[]) => response),
catchError((error) => _throw(error)),
);
}
Tôi sẽ đánh giá cao nó nếu ai đó nhìn vào mã và xem những gì tôi đã bỏ lỡ. Cảm ơn.
BIÊN TẬP
Sau khi đề xuất của bạn @polyglot, một số lỗi đã biến mất chỉ có vấn đề với đường ống không đồng bộ và ngFor cho mảng này như trong hình bên dưới và có lỗi managementNameControl cho this.filteredEFastees [index].
Loại 'Có thể quan sát được <Có thể quan sát được <IE Jobee [] >>' không thể gán cho loại 'Có thể quan sát được'. Loại 'Observable <IE Jobee []>' bị thiếu các thuộc tính sau từ loại 'IE Jobee': id, firstName,
Trả lời
Đầu tiên, bạn đã không khởi tạo filteredEmployees. Nên là:
filteredEmployees: Observable<IEmployee>[] = []; // Not Observable<IEmployee[]>
Tiếp theo, bạn đã sử dụng [formGroupName]="j"hai lần trong create-project.html. Xóa <ng-container [formGroupName]="j">trình bao bọc. Và bạn nên bắt đầu với [formGroup]="createProjectForm".
<section [formGroup]="createProjectForm">
<div formArrayName="projectTeamMembers" class="single-item-container"
*ngFor="let t of createProjectForm.get('projectTeamMembers').controls; let j = index">
<div class="spinner" *ngIf="showLoader">
<mat-progress-spinner [color]="'primary'" diameter="100" mode="indeterminate" value="50">
</mat-progress-spinner>
</div>
<div [formGroupName]="j" *ngIf="!showLoader" fxLayout="row" fxLayoutGap="2%">
<!-- employee -->
<mat-form-field fxFlex="100%">
<input matInput formControlName='firstName' placeholder="Start typing employee first or last name."
[matAutocomplete]="auto">
<mat-error *ngIf="t.get('firstName').errors?.required">
{{ 'FIELD_REQUIRED_MESSAGE' | translate }}
</mat-error>
</mat-form-field>
<mat-autocomplete #auto="matAutocomplete" [displayWith]="employeeTypeaheadDisplayFn" (optionSelected)="selectEmployee($event.option.value.id)">
<mat-option *ngFor="let employee of filteredEmployees[j] | async" [value]="employee">
{{ employee.firstName }} {{ employee.lastName }}
</mat-option>
</mat-autocomplete>
<div class="input-bottom">
<button mat-raised-button color="warn" (click)="removeProjectTeamMemberItem(j, t.value)">
Delete
</button>
</div>
</div>
</div>
<div class="form-footer">
<div class="items-buttons">
<button mat-raised-button color="primary" type="button"
(click)="addProjectTeamMember()">{{'COMPONENTS.PROJECT.ADD_NEW_TEAM_MEMBER' | translate}}</button>
</div>
</div>
</section>
ĐÃ GIẢI QUYẾT
Tôi đã khắc phục sự cố được lọcEmyployee cần phải
LọcE Nhân viên: IE Jobee [] và phương thức managementNameControl trông như thế nào
manageNameControl(index: number) {
var arrayControl = this.createProjectForm.get('projectTeamMembers') as FormArray;
arrayControl.at(index).get('employeeId').valueChanges
.pipe(
debounceTime(300),
switchMap((value) => this.projectManagementService.filterEmployees(value)),
)
.subscribe((employees: IEmployee[]) => (this.filteredEmployees = employees));
}
và loại bỏ các đường ống aync với từ dạng html
<mat-form-field fxFlex="100%">
<input matInput formControlName='employeeId' name='employeeId' placeholder="Start typing employee first or last name."
[matAutocomplete]="auto">
<mat-error *ngIf="t.get('employeeId').errors?.required">
{{ 'FIELD_REQUIRED_MESSAGE' | translate }}
</mat-error>
</mat-form-field>
<mat-autocomplete #auto="matAutocomplete" [displayWith]="employeeTypeaheadDisplayFn(filteredEmployees)">
<mat-option *ngFor="let employee of filteredEmployees" [value]="employee.id">
{{ employee.firstName }} {{ employee.lastName }}
</mat-option>
</mat-autocomplete>