Carlos Cifuentes
AngularJS → Angular reference

ng-form / nested forms in modern Angular

Nested ng-form elements become nested FormGroups. A repeated ng-form becomes a FormArray of groups, defined in the component.

Before · AngularJS
<form name="orderForm" ng-submit="vm.save()">
  <input name="customer" ng-model="vm.order.customer" required>
  <ng-form name="lineForm" ng-repeat="line in vm.order.lines">
    <input name="sku" ng-model="line.sku" required>
    <input name="qty" type="number" ng-model="line.qty" min="1">
    <span ng-show="lineForm.qty.$invalid">Invalid quantity</span>
  </ng-form>
</form>
After · Angular
newLine = () => this.fb.group({ sku: ['', Validators.required], qty: [1, Validators.min(1)] });
form = this.fb.group({
  customer: ['', Validators.required],
  lines: this.fb.array([this.newLine()]),
});

<form [formGroup]="form" (ngSubmit)="save()">
  <input formControlName="customer" />
  @for (line of form.controls.lines.controls; track line) {
    <div [formGroup]="line">
      <input formControlName="sku" />
      <input formControlName="qty" type="number" />
    </div>
  }
</form>

What changes

  • ng-form inside ng-repeat becomes a FormArray; each row is a FormGroup bound with [formGroup].
  • Validity still propagates upward: one invalid row makes the whole form invalid.
  • Rows are added and removed with push() and removeAt() on the FormArray, and form.getRawValue() returns a typed object.

Migration tip. Rules that span several rows, such as no duplicate SKUs, become a validator on the FormArray. In AngularJS those checks usually lived in controller code that ran on submit.

Related

Planning a migration or a micro-frontend platform?

In a 20-minute call you describe your situation and I tell you how I'd approach it. If it isn't worth doing yet, I'll say so.

Message me on LinkedIn