3

I am trying to print get the value of Form Controls of Nested form on Console as well as in HTML.

userForm = new FormGroup({
    name: new FormControl("Tom Alter"),
    address: new FormGroup({
        Country: new FormControl("India"),
        State: new FormControl("Delhi")
    })
});

In Both the cases, I am able to find the value using get statement.

console.log ("name : ", this.userForm.controls.name.value);
console.log ("Country using Get Way 1  : ", this.userForm.get(['address', 'Country']).value) ;
console.log ("Country using Get Way 2 : ", this.userForm.get(['address']).get(['Country']).value);
console.log ("Country using Get Way 3 : ", this.userForm.get(['address.Country']).value);
console.log ("Country without Get: ", this.userForm.group.address.controls.cCountry.value);

Out of these "Name", "Way1", "Way2" are working but, "Way 3" and "Without get" is not working as it is working for "name"

Similarly in HTML :

Name : {{userForm.controls.name.value}}
<br>
<br>
Country with get Way - 1 : {{userForm.get(['address']).get(['Country']).value}}
<br>
Country with get Way - 2 : {{userForm.get(['address','Country']).value}}
<br>
<br>
Country without get: {{userForm.address.controls.country.value}}

name and Way 1 is working fine, where as "Way-2" and "Without get" is not working.

Please point me to my mistake in the code.

Code is available on https://stackblitz.com/edit/angular-nestedformgroups

0

3 Answers 3

6

way 3 should be without array

this.userForm.get('address.Country').value

Country without Get can be accessed through controlls

this.userForm.controls.address.controls.Country.value

in the template there is just a small mistake. you should have Country instead of country and also access through .controls propery

{{userForm.controls.address.controls.country.value}}
Sign up to request clarification or add additional context in comments.

Comments

3

We've been facing at work a lot of issues with form and nested forms. After a lot of research around that topic to simplify our lives we came up with a library that we decided to open source. It's a super tiny wrapper that you can use for both reactive or template forms (would definitely recommend reactive ones though).

The library is called ngx-sub-form: https://github.com/cloudnc/ngx-sub-form The readme should contain everything you need to discover the library but I've also written an article here: https://dev.to/maxime1992/building-scalable-robust-and-type-safe-forms-with-angular-3nf9 to go more into details.

Now, I've transformed your stackblitz to use ngx-sub-form, here's how it'd look:

https://stackblitz.com/edit/user-nested-form-group?file=src/app/app.component.ts

Code:

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  public userUpdate(user: User): void {
    // every time the form changes
    // this method will be called
    console.log(user);
  }
}

app.component.html

<app-user-form (userUpdate)="userUpdate($event)"></app-user-form>

user-form.component.ts

@Component({
  selector: "app-user-form",
  templateUrl: "./user-form.component.html",
  styleUrls: ["./user-form.component.css"]
})
export class UserFormComponent extends NgxAutomaticRootFormComponent<User> {
  @DataInput()
  @Input("user")
  public dataInput: Required<User>;

  @Output("userUpdate")
  public dataOutput: EventEmitter<User> = new EventEmitter();

  protected getFormControls(): Controls<User> {
    return {
      name: new FormControl(null),
      address: new FormControl(null),
    };
  }
}

user-form.component.html

<div [formGroup]="formGroup">
  <input type="text" [formControlName]="formControlNames.name" placeholder="Name">
  <app-address-control type="text" [formControlName]="formControlNames.address" placeholder="Address"></app-address-control>
</div>

<pre>{{ formGroupValues | json}}</pre>

<!-- So you can simply do: -->

<ul>
  <li>Name: {{ formGroupValues.name }}</li>
  <li>
    Address
    <ul>
      <li>Country: {{ formGroupValues.address.country }}</li>
      <li>State: {{ formGroupValues.address.state }}</li>
    </ul>
  </li>
</ul>

In the above, notice how easy it is to access the nested values

address-control.component.ts

@Component({
  selector: "app-address-control",
  templateUrl: "./address-control.component.html",
  styleUrls: ["./address-control.component.css"],
  providers: subformComponentProviders(AddressControlComponent)
})
export class AddressControlComponent extends NgxSubFormComponent<
  Address
> {
  protected getFormControls(): Controls<Address> {
    return {
      country: new FormControl(null),
      state: new FormControl(null)
    };
  }
}

address-control.component.html

<div [formGroup]="formGroup">
  <input type="text" [formControlName]="formControlNames.country" placeholder="Country">
  <input type="text" [formControlName]="formControlNames.state" placeholder="State">
</div>

This is not the place to explain all the features of the library so I'll let you dig into the readme or article but by doing so you'll get extra type safety too when using AoT and many more things.

When looking at the demo also open the console to see that you can easily react whenever the form changes.

Comments

0

For Country without get : Replace "{{userForm.address.controls.country.value}}" with {{userForm.controls['address'].controls['Country'].value}}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.