Disable FormGroup not working as expected

Viewed 1395

When initializing a FormGroup and disabling the FormGroup or FormControl in a HttpClient.get callback, the FormGroup is not disabled in HTML, but the disabled property reports as true.

Please see working example here

I can fix the issue by wrapping the disabled code in a timeout as below, but this is not desirable:

setTimeout(() => {
    this.form.disable();
});

It does work when not setting the FormGroup to a new instance, but I would like to set it to a new instance.

Minimal example to reproduce the issue:

import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { PersonService } from './person.service';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'my-app',
  template: `  
        <form [formGroup]="form">    
        <button class="btn btn-primary" (click)="onFetchPerson()">Click Me</button>                
            <div class="form-group">
                <label>First Name</label>
                <input type="text" class="form-control" formControlName="firstName" />
            </div>
            <div class="form-group">
                <label>Surname</label>
                <input type="text" class="form-control" formControlName="surname" />
            </div>
            <div class="form-group">                
                Disabled:{{form.disabled}}<br>
                Status:{{form.status}}
            </div>
        </form>
    `,
})
export class App implements OnInit {  
  public form: FormGroup;

  constructor(private personService: PersonService) {}

  ngOnInit(): void {
    this.form = new FormGroup({     
      firstName: new FormControl(),
      surname: new FormControl(),
    });
  }

  public onFetchPerson() {
    this.personService.fetchPerson().subscribe(() => {
      this.form = new FormGroup({        
        firstName: new FormControl('John'),
        surname: new FormControl('Doe'),
      });
      this.form.disable();
      console.log(this.form);
    });
  }
}

@Injectable({
  providedIn: 'root',
})
export class PersonService {
  constructor(private http: HttpClient) {}

  public fetchPerson = () => this.http.get('https://randomuser.me/api');
}

@NgModule({
    imports: [BrowserModule, HttpClientModule, ReactiveFormsModule],
    declarations: [App],
    bootstrap: [App],
    providers: [
        PersonService
    ]
})
export class AppModule {}

enter image description here

3 Answers

you can use the ChangeDetectorRef for your problem

here's an example

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

export class App implements OnInit {
    constructor(private personService: PersonService, readonly cd: ChangeDetectorRef) {}

  public onFetchPerson() {
    this.personService.fetchPerson().subscribe(() => {

      this.form = new FormGroup({
        firstName: new FormControl('John'),
        surname: new FormControl('Doe'),
      });
      this.cd.detectChanges();
      this.form.disable();
      console.log(this.form);
    });
  }
}

For me it worked if you just set the value instead of passing a whole new instance of the formGroup

 this.personService.fetchPerson().subscribe(() => {
      this.form.setValue({
        firstName:'John',
        surname:'Doe'
      });
      this.form.disable();
      console.log(this.form);
    });

I would use FormBuilder, this is a very tidy way of creating your form and adding validation.

Having created the form, this allows you to patch (partially update) the form. To set values you need to have all the properties in your object.

The FormBuilder provides syntactic sugar that shortens creating instances of a FormControl, FormGroup, or FormArray. It reduces the amount of boilerplate needed to build complex forms.

From angular.io

Plunk here

  import { FormGroup, FormControl, FormBuilder } from '@angular/forms';

  constructor(
    private personService: PersonService, 
    private fb: FormBuilder
  ) {}

  ngOnInit(): void {
    this.form = this.fb.group({
      firstName: [''],
      surname: [''],
    });
  }

  public onFetchPerson() {
    this.personService.fetchPerson().subscribe(() => {
      this.form.patchValue({ firstName: 'John', surname: 'Doe' });
      this.form.disable();
      console.log(this.form);
    });
  }
Related