I'm working on a Angluar 7 project with Angular-Material and I'm using reactive forms the first time. I've implemented an AutoComplete so the user can select an employee from a list of EmployeeObjects. The form uses Angular reactive forms. The objects of the employees are much more complex than the user needs to know.
The selection of an employee and the storing and updating of the reactive form works fine. The problem is that the shown value in the input field looks like [object: object], because the whole object will set to the [value] of the input field.
When I implement a getter to show only the employee name the shown value looks correct, but the reactive form value only stores the formatted string instead of the whole object.
How is it possible to do both, show the correct string to the user and store the whole value in the form?
Thanks for your help.
Stackblitz
Class
@Component({
selector: 'app-employee-data',
templateUrl: './employee-data.component.html',
styleUrls: ['./employee-data.component.scss']
})
export class EmployeeDataComponent implements OnInit {
employeeForm: FormGroup;
employeeCtrl = new FormControl();
employees: Employee[] = EmployeeList as Employee[];
filteredEmployees: Observable<Employee[]>;
result;
@Input() employee: Employee;
@ViewChild(MatAutocomplete) matAutocomplete: MatAutocomplete;
constructor(private formBuilder: FormBuilder) {
this.initEmployeeFilters(this.employeeCtrl);
this.employeeForm = this.createFormGroupWithBuilder(formBuilder);
}
ngOnInit() {
}
private _filterStates(value: string): Employee[] {
const filterValue = value.toLowerCase();
return this.employees.filter(employee => employee.lastname.toLowerCase().indexOf(filterValue) === 0);
}
public getFullname(employee: Employee): string {
return employee.lastname + ', ' + employee.firstname;
}
public getEmployee(): Employee {
return JOHN_DOE;
}
private initEmployeeFilters(formCtrl: FormControl) {
this.filteredEmployees = formCtrl.valueChanges
.pipe(
startWith(''),
map(employee => employee ? this._filterStates(employee) : this.employees.slice())
);
}
createFormGroupWithBuilder(formBuilder: FormBuilder) {
return formBuilder.group({
employeeData: formBuilder.group({
employee: new FormControl(),
}),
});
}
revert() {
this.employeeForm.reset();
this.employeeForm.reset({ employeeData: new Employee() });
}
onSubmit() {
this.result = Object.assign({}, this.employeeForm.value);
this.result.employeeData = Object.assign({}, this.result.employeeData);
}
}
Template
<form [formGroup]=„employeeForm" (ngSubmit)="onSubmit()" novalidate>
<div formGroupName="employeeData" novalidate>
<mat-form-field>
<input
matInput
type="text"
placeholder="Name"
[matAutocomplete]="auto"
formControlName="name"
>
<mat-autocomplete #auto="matAutocomplete">
<mat-option
*ngFor="let employee of employees | async"
[value]="getEmployee(employee)"
>
<img
[src]="employee.profilePicture"
height="25"
>
<span>{{employee.lastname}}, {{employee.firstname}}</span>
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<button type="submit" [disabled]="employeeForm.pristine">Save</button>
</form>
Employee class and List of Employees
export class Employee {
id = 1;
lastname = '';
firstname = '';
}
export const JANE_DOE = {
id: 1,
lastname: 'Doe',
firstname: 'Jane',
profilePicture: ‚url‘
};
export const JOHN_DOE = {
id: 2,
lastname: 'Doe',
firstname: 'John',
profilePicture: ‚url‘
};
export const EmployeeList: Employee[] = [
JANE_DOE,
JOHN_DOE,
];