Miguel Moura
Miguel Moura

Reputation: 39474

Where to initialise a FormGroup in Reactive forms?

Using Angular 11 with Typescript 4 in Strict Mode I have:

export class ContactComponent implements OnInit { 

  form: FormGroup;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {

    this.form = this.formBuilder.group({ 
      email: ['', [Validators.required, Validators.email]],
      name: ['', [Validators.required, Validators.maxLength(40)]],
    });

  }

I get the build error:

 Property 'form' has no initialiser and is not definitely assigned in the constructor.

Shouldn't the FormGroup be initialised on ngOnInit?

Upvotes: 12

Views: 12157

Answers (2)

Bullsized
Bullsized

Reputation: 607

It is perfectly fine to declare the FormGroup in:

  • the constructor;
  • a lifecycle hook;
  • as a class property.

Option one:

  myForm: FormGroup;

  constructor(private formBuilder: FormBuilder) {
    this.myForm = this.formBuilder.group({
      // Define your form controls here
    });
  }

Option two:

  myForm: FormGroup;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.myForm = this.formBuilder.group({
      // Define your form controls here
    });
  }

Option three:

  myForm: FormGroup = new FormGroup({
    // Define your form controls here
  });

  constructor() {}

Upvotes: 1

BizzyBob
BizzyBob

Reputation: 14750

Shouldn't the FormGroup be initialised on ngOnInit?

It doesn't have to be; I find it simplest to initialize most things directly on the class like this:

export class ContactComponent implements OnInit { 

  form = this.formBuilder.group({ 
    email: ['', [Validators.required, Validators.email]],
    name:  ['', [Validators.required, Validators.maxLength(40)]],
  });

  constructor(private formBuilder: FormBuilder) { }

}

This works fine with strictPropertyInitialization.

The exception is when initializing something that requires data from the DOM (@Input, @ViewChild, etc) Since those things get initialized in the various Lifecycle Hooks as described in this answer:

  • @Input()ngOnInit
  • @ViewChild()ngAfterViewInit
  • @ContentChildren()ngAfterContentInit

Initializing something that depends on say, an @Input(), would be done in the corresponding lifecycle hook, ngOnInit, however, this does not appease the strict rule, so the Definite Assignment Assertion Operator ! is needed.

export class ContactComponent implements OnInit { 
  @Input() input!: number;

  inputDoubled!: number;
  
  form = this.formBuilder.group({ 
    email: ['', [Validators.required, Validators.email]],
    name:  ['', [Validators.required, Validators.maxLength(40)]],
  });

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.inputDoubled = this.input * 2;
  }
}

Upvotes: 18

Related Questions