0

Give the following, how can I make my optional properties be optional inside the FormBuilder?

export type TypedFormControls<T extends Record<any, any>> = {
  [K in keyof T]-?: T[K] extends Array<infer R>
    ? FormArray<
        R extends Record<any, any>
          ? FormGroup<TypedFormControls<R>>
          : FormControl<R>
      >
    : T[K] extends Record<any, any>
    ? FormGroup<TypedFormControls<T[K]>>
    : FormControl<T[K]>;
};

Here are my models

export class UserModel {
  email: string;
  age?: number;
  information?: Information;
}

export class Information {
  id: number;
  name: string;
  gender?: string;
}

And finally the form group

this.formGroup = this._formBuilder.group<TypedFormControls<UserModel>>({
      email: this._formBuilder.control('email@email'),
      // age: this._formBuilder.control(25),
      information: this._formBuilder.group<TypedFormControls<Information>>({
        // gender: this._formBuilder.control('male'),
        id: this._formBuilder.control(1),
        name: this._formBuilder.control('John'),
      }),
    });

Here is the stackblitz

3
  • stackblitz link broken Commented Sep 12, 2023 at 14:51
  • I would avoid using a formBuilder at all, and just build the form up manually, and not assign validators.required to those optional controls. Commented Sep 12, 2023 at 14:55
  • @AndrewAllen it should be working now. Commented Sep 12, 2023 at 15:03

2 Answers 2

0

https://stackblitz.com/edit/angular-ivy-fqjstc?file=src%2Fapp%2Fapp.component.ts

import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';

export type TypedFormControls<T extends Record<any, any>> = {
  [K in keyof T]-?: T[K] extends Array<infer R>
    ? FormArray<
        R extends Record<any, any>
          ? FormGroup<TypedFormControls<R>>
          : FormControl<R>
      >
    : T[K] extends Record<any, any>
    ? FormGroup<TypedFormControls<T[K]>>
    : FormControl<T[K]>;
};

export class UserModel {
  email: string;
  age: number | null;
  information: Information | null;
}

export class Information {
  id: number;
  name: string;
  gender: string | null;
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
  formGroup: FormGroup;

  constructor(private readonly _formBuilder: FormBuilder) {}

  ngOnInit(): void {

    this.formGroup = this._formBuilder.group<TypedFormControls<UserModel>>({
      email: this._formBuilder.control('email@email'),
      age: this._formBuilder.control(25),
      information: this._formBuilder.group<TypedFormControls<Information>>({
        gender: this._formBuilder.control('male'),
        id: this._formBuilder.control(1),
        name: this._formBuilder.control('John'),
      }),
    });
  }
}

Sign up to request clarification or add additional context in comments.

3 Comments

I redefined your nullable types with | null.
But the idea is to have those nullable properties be optional inside the formbuilder - the TypeFormControls needs some reworking, I just don't know how to rework it to allow for optional properties.
A property defined as string | null is a nullable property. It can take either a string or null. If your problem is validation, then just don't use a FormBuilder, but build it up yourself. Honestly I think it's easier than a form builder. Then don't add Validators.required to the properties that aren't required.
0

I just realized that the initial example is making all properties required, so instead of [K in keyof T]-? if I use [K in keyof T] the optional properties remain which is exactly the result I am looking for.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.