I want to build a form which can have multiple filters. Each filter consists of a fieldName, operator and a value. The type of the value is related to the fieldName.
This is my filterModel:
export type FilterModel<T> = { [K in keyof T]: {
fieldName: K | null,
fieldNameData: DisplayValue<K>[];
operator: FilterOperator | null,
operatorData: DisplayValue<FilterOperator>[],
value: T[K] | null
} }[keyof T]
With which I can achieve the following:
interface User {
name: string;
age: number;
}
const userFilter: FilterModel<User> = {
fieldName: 'age',
fieldNameData: [],
operator: FilterOperator.Contains,
operatorData: [],
value: 3
}
const userFilter: FilterModel<User> = {
fieldName: 'age',
fieldNameData: [],
operator: FilterOperator.Contains,
operatorData: [],
value: '' <-- Error because number is expected for field 'age'
}
Now I want to build a generic filter component, that is passed a FilterModel of any type (FilterModel<T>). This component defines the controls in the template etc. I also created a mapped type so I can use any model in a typed FormGroup:
export type FormGroupModel<T> = {
[Property in keyof T] : FormControl<T[Property]>;
}
What works:
public workingForm = new FormGroup<FormGroupModel<FilterModel<User>>>({
fieldName: new FormControl('name'),
fieldNameData: new FormControl([], { nonNullable: true }),
operator: new FormControl(null),
operatorData: new FormControl([], { nonNullable: true }),
value: new FormControl(''),
});
I can use it without a problem in my template (the control attribute is expecting a FormControl):
<dropdown-field [control]="workingForm.controls.fieldName"></dropdown-field>
What doesn't work:
export class FilterComponent<T> implements OnInit {
@Input() public notWorkingForm! = new FormGroup<FormGroupModel<FilterModel<T>>>(); // this is should be created by parent
But my template has now an error
<dropdown-field [control]="notWorkingForm.controls.fieldName"></dropdown-field>
Somehow, when using a generic type, I am not receiving FormControls, but Abstract Controls. I am not sure what I'm doing wrong. I believe something like this should be possible with the new typed forms in angular 14.
Can someone help? I really would like to have a type safe form here.
EDIT
I noticed that I cannot set the generic Input "form" because I always get "Type is not assignable". Maybe my approach is generally wrong?
