Home > Net >  Angular 14 strictly typed reactive forms - How to type FormGroup model using existing interface
Angular 14 strictly typed reactive forms - How to type FormGroup model using existing interface

Time:06-06

I'm just playing around with new angular typed forms api and couldn't figure out how to type FormGroup without declaring specific "FormInterface" witch has to match the original one.

Maybe I'm missing something or it's just impossible to do so.

I was able to make thing working correctly (example below), but what I'm not a fan of here is declaration of UserForm interface witch has no reference to User interface and has to be a mirror copy of it but with FormControl<> fields.

Is it possible in case like this to type FormGroup just with User interface?.

Full working example available on stackblitz

user.model.ts

export interface User {
  firstName: string;
  lastName: string;
  email: string;
  age: number | null;
}

user.service.ts

@Injectable()
export class UserService {

  add(user: User): void {
    console.log('Add user', user);
  }

}

app.component.ts

interface UserForm {
  firstName: FormControl<string>;
  lastName: FormControl<string>;
  email: FormControl<string>;
  age: FormControl<number | null>;
}

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

  constructor(private userService: UserService) {}

  ngOnInit(): void {
    this.form = new FormGroup({
      firstName: new FormControl<string>('', { nonNullable: true }),
      lastName: new FormControl('', { nonNullable: true }),
      email: new FormControl('', { nonNullable: true }),
      age: new FormControl<number | null>(null),
    });
  }

  submitForm(): void {
    this.userService.add(this.form.getRawValue());
  }
}

CodePudding user response:

You can try using a definite assignment to your form variable. Below is the code:

form!: FormGroup;

You can also use your declaration to initialize the form controls since you're 'posting' values on the form and not yet updating.

form: FormGroup = new FormGroup({
      firstName: new FormControl<string>('', { nonNullable: true }),
      lastName: new FormControl('', { nonNullable: true }),
      email: new FormControl('', { nonNullable: true }),
      age: new FormControl<number | null>(null),
    });

Using another interface for a form that's not related to your main interface is really taxing in resources and redundant.

CodePudding user response:

You cannot use User as the type of FormGroup. You can however reference User in UserForm with enums then use UserForm as a type of FormGroup. Check out #72500855 on strongly typed forms with Angular 14 since your question is a potential duplicate of it.

CodePudding user response:

As mentioned in the RFC,

FormGroup's generic type is an interface that describes the types of each of its inner controls.

May be you can create helper method to reduce boilerplate code

function makeNonNullableFormControl<T>(value: T): FormControl<T> {
  return new FormControl(value, {nonNullable:true});
}

function makeFormControl<T>(value: T | null): FormControl<T | null> {
  return new FormControl(value);
}

this.form = new FormGroup({
        firstName: makeNonNullableFormControl(''),
        lastName: makeNonNullableFormControl(''),
        email: makeNonNullableFormControl(''),
        age: makeFormControl<number>(null),
});
  • Related