I want to make use of typed forms in Angular.
In my scenario I have a form group that should have some properties.
All of them should be nullable and start with an initial value of "null".
But they should also be typed.
I also want to use the form builder to make my code short & concise.
However, I am failing to do what I want.
One of my approaches looks like this:
formGroup = this.fb.group<{
User: FormControl<string | null>,
Site: FormControl<string | null>,
AccessLevel: FormControl<string | null>,
Application: FormControl<string | null>,
BusinessProcessArea: FormControl<string | null>,
}>({
User: [null, Validators.required],
Site: [null, Validators.required],
AccessLevel: [null, Validators.required],
Application: [null, Validators.required],
BusinessProcessArea: [null, Validators.required],
});
However, typescript does not like what I am doing and throws an error here.
Also I need to double all the properties what makes this piece of code also hard to maintain.
I would love to do something like this:
formGroup = this.fb.group({
User<string>: [null, Validators.required],
Site<string>: [null, Validators.required],
AccessLevel<string>: [null, Validators.required],
Application<string>: [null, Validators.required],
BusinessProcessArea<string>: [null, Validators.required],
});
I know that this is not valid Typescript and that I cannot put the type definition there.
But this should show my wish to:
How can I achieve this?
I find that defining an interface for my typed forms gives me a clearer syntax overall. An example is given below:
// person-form.model.ts
export interface IPersonForm {
firstName: FormControl<string | null>;
lastName: FormControl<string | null>;
identifier: FormControl<string | null>;
}
// person-form.component.ts
@Component({
selector: 'app-person-form',
standalone: true,
imports: [],
templateUrl: './person-form.component.html',
styleUrl: './person-form.component.scss',
})
export class PersonFormComponent
implements OnInit
{
private fb = inject(FormBuilder);
public personForm!: FormGroup<IPersonForm>;
ngOnInit(): void {
this.buildForm()
}
private buildForm(): void {
this.personForm = this.fb.group({
firstName: [null, [Validators.required]],
lastName: [null, [Validators.required],
identifier: [null, [Validators.maxLength(255)]],
});
}
Additionally, unless you have a specific need for null I would recommend typing the controls as string only and defining the initial value as empty string - this is a 'falsy' value and will trigger the required validator correctly without the use of null.