I want to implement form for my expenses tracking app. This form includes name, price, date, and category. The categories list is unique for each individual user, so I perform API request to get all the categories user has. Special component is responsible for this job in front-end :
@Component({
selector: 'app-category-select',
templateUrl: './category-select.component.html',
styleUrls: ['./category-select.component.css'],
providers: [
{ provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CategorySelectComponent),
multi: true
}
]
})
export class CategorySelectComponent implements OnInit, ControlValueAccessor {
categories: Category[] = [];
@Input() parentForm! : FormGroup;
@Output() categoryEvent = new EventEmitter<number>();
catId!: number
categoryId!: number
constructor(private categoryService: CategoriesService) {}
onChange: any = () => {}
onTouch: any = () => {}
setCatId(categoryId: number){
if( categoryId !== undefined && this.categoryId !== categoryId){
this.categoryId = categoryId
this.onChange(categoryId)
this.onTouch(categoryId)
}
}
writeValue(obj: any): void {
this.catId = obj
}
registerOnChange(fn: any): void {
this.onChange = fn
}
registerOnTouched(fn: any): void {
this.onTouch = fn
}
setDisabledState?(isDisabled: boolean): void {
}
constructor(private categoryService: CategoriesService) {}
ngOnInit(): void {
this.categoryService.findAll(parseInt(localStorage.getItem(environment.userIdName) || '')).subscribe(
result => this.categories = result
)
}
changeCategory(categoryId: number){
this.categoryEvent.emit(categoryId)
}
}
...
<mat-form-field appearance="fill" *ngIf="parentForm" [formGroup]="parentForm">
<mat-label>Select category</mat-label>
<mat-select #categoryId [formControlName]="'category'" [(ngModel)] = "catId">
<mat-option *ngFor="let category of categories" value="{{category.id}}">{{category.name}}</mat-option>
</mat-select>
</mat-form-field>
This component is a part of my main form for adding or editing expenses:
<form [formGroup]="form" (ngSubmit)="onSubmit()">
...
<div class="input-field">
<app-category-select [parentForm]="form"></app-category-select>
</div>
</form>
And ts-file:
this.form = new FormGroup({
name: new FormControl(null, Validators.required),
price: new FormControl(null, [Validators.required, Validators.pattern('[0-9]+(\.[0-9][0-9]?)?')]),
category: new FormControl(null, Validators.required),
date: new FormControl(null, Validators.required)
})
The problem: When I'm trying to edit expense using form.patchValue() and updateTextFields() from materialize library I want all fields to display the current expenses data. But it updates all fields except the categories:
if(expense){
this.expense = expense
this.form.patchValue({
name: expense.name,
price: expense.price,
date: new Date(expense.date),
category: expense.categoryDTO.id
})
MaterialsService.updateTextInputs()
}
Form itself includes the category value, but how to get it in view?