Search code examples
angularangular-formsangular2-formbuilder

Angular Form Group reinitialize


In Angular 8, I have a Form group where I want to reinitialize the form with new values. But when I do fb.build the second time, the values are not displayed correctly.

The checkbox becomes non-checked even though it should be checked and the input field shows [object Object]

<form [formGroup]="myform" novalidate autocomplete="off">
    <mat-checkbox
      formControlName="dndcheckbox"
      [(ngModel)]="userdetails.DoNotDisturb"
    ></mat-checkbox>
    <mat-form-field>
      <input matInput type="text" formControlName="fwdNumber" [(ngModel)]="userdetails.ForwardNumber" />
    </mat-form-field>
</form>

userdetails: MyObject;
myform: FormGroup;
constructor(private fb: FormBuilder,) {}

ngOnInit() {
      this.myService.refreshDataSubject.subscribe((data) => {
        this.userdetails = data;
        this.initializeForm();
      });
}

initializeForm() {
    this.myform = this.fb.group({
      dndcheckbox: ['', ''],
      fwdNumber: [
        {
          value: this.userdetails.ForwardNumber,
        },
        control => validateTelephoneNumber(this.userdetails.ForwardNumber),
      ],
    });
}

What could be going wrong?


Solution

  • I think the problem is in your data. The structure of your userdetails object and the data object that comes from your service that you subscribed is not same. may be data doesn't have the same signature of userdetails. console it to check if it is ok or not.

    Additional: Your are creating the form every time the data changes but here only the value is changed not the form skeleton. So, I think you can create the form only once and when the data changes just update the form with the new value that comes from your service.

    As, I am not sure about your object structure, Here I assume your service returns data object like this { IsDndChecked: true, ForwardNumber: '123245' }

      ngOnInit() {
        this.initializeForm();
    
        this.myService.refreshDataSubject.subscribe((data) => {
          this.userdetails = data;
          this.updateFormValue(data);
        });
      }
    
      initializeForm() {
          this.myform = this.fb.group({
            dndcheckbox: [''],
            fwdNumber: ['', this.validateTelephoneNumber],
          });
      }
    
      validateTelephoneNumber(control: AbstractControl) {
        alert(control.value);
      }
    
      updateFormValue(data: any) {
        this.myform.setValue({
          dndcheckbox: data.IsDndChecked,
          fwdNumber: data.ForwardNumber
        });
      }
    

    here Inside ngOnInit() I call the method initializeForm() to create the form. I am constructing the form once and when the data change updateFormValue() is called to update the value of the form.

    Another thing, you can set a validator function this way fwdNumber: ['', this.validateTelephoneNumber] and no need to pass the value (look I am not sending the value as parameter).

    When you update the value of the field (you can update the value from UI or using function like setValue() or patchValue(). for more info about this two function of angular reactive form see here) the specific control automatically passed to its custom validator function.

    If you see the code snippet above, you will find I didn't send any parameter but my method implementation

    validateTelephoneNumber(control: AbstractControl) {
        alert(control.value);
      }
    

    is expecting the particular fwdNumber form control.

    In this way the code is more cleaner and controllable. Hope it helps.