'ERROR Error: Cannot find control with path: 'products -> Quantity'

When I add one product in my form, show this error. My code ts:

this.products = this.ps.getProduct();

this.addform = this.fb.group({
  'invoice_number': new FormControl('', [Validators.required, Validators.nullValidator]),
  'Subtotal': new FormControl('', Validators.required),
  'products': this.fb.array([
  ]),
  'total': new FormControl('', Validators.required),
});

Model class:

export class Sale {
    invoice_number: number;
    products: Products[];
}

My HTML code:

    <form [formGroup]="addform" (ngSubmit)="onaddsale()">
      <div class="contant">
        <div class="row">
          <div class="input-field col s4">
           <input formControlName="invoice_number" id="invoice_number" type="text" class="validate">
          </div>
    </div>
    </div>
          <tr formArrayName="products" class="group" style="cursor: pointer" *ngFor="let item of products; index as i" [formGroupName]="i">
            <td>
              <input formControlName="Subtotal" [(ngModel)]="item.Subtotal" readonly type="number" />
            </td>
            <td>
              <input formControlName="total" [(ngModel)]="item.total" readonly type="number" />
            </td>          
          </tr>
</form>

In my HTML doesn't display nothing, also show my error in console.

Can you suggest what is the problem, how to solution this?



Solution 1:[1]

Try adding formGroupName like:

<form [formGroup]="addform" (ngSubmit)="onaddsale()">
  <div class="contant">
    <div class="row">
      <div class="input-field col s4">
        <input formControlName="invoice_number" id="invoice_number" type="text" class="validate">
      </div>
    </div>
  </div>
  <tr formArrayName="products" class="group" style="cursor: pointer" *ngFor="let item of products; index as i">
    <div [formGroupName]="i">
      <td>
        <input formControlName="subtotal" readonly type="number" />
      </td>
      <td>
        <input formControlName="total" readonly type="number" />
      </td>
    </div>
  </tr>
</form>

Solution 2:[2]

More slow I think you have a service ps that have a method getProducts() some like

getProduct(id:any)
{
     return this.httpClient.get("url/"+id);
}

the url/Id return you a json like, e.g.

'invoice_number':222152
'product':[
   {item:'some',total:120,subtotal:130},
   {item:'other',total:110,subtotal:140}
]

Well, you must subscribe in ngOnInit to the service and, when you get the data create a formGroup

ngOnInit()
{
    this.ps.getProduct('123').subscribe((data:any)=>{
        this.createform(data)
    }
}
//see that createForm is a function that return a formGroup
//this formGorup have two fields, "invoice_number" and "products"
 //products is an array. We use a function that return a array 
 //of controls and "products" is thif.fb.array(the array of controls)
createForm(data:any)
{
      return this.fb.group({
           invoice_number:[data? data.invoice_number:null,
                   [Validators.required, Validators.nullValidator]],
           products:this.fb.array(this.getProducts(data? data.products:null)
      })
}
//getProducts return an array of Controls -really an array of group controls-
getProducts(products:any)
{
   let controls[]=[];
   if (products)
   {
      products.forEach(x=>{
         controls.push(
             this.fb.group({
                  total:[x.total,Validators.required]
                  subtotal:[x.total,Validators.required]

             }
         );
      }
   }
   return controls;
}

Then your html it's like

<form [formGroup]="addform" (ngSubmit)="onaddsale()">
      <div class="contant">
        <div class="row">
          <div class="input-field col s4">
           <input formControlName="invoice_number" id="invoice_number" type="text" class="validate">
          </div>
    </div>
    </div>
          <tr formArrayName="products" class="group" style="cursor: pointer" *ngFor="let item of products; index as i" [formGroupName]="i">
            <td>
              <input formControlName="subtotal" readonly type="number" />
            </td>
            <td>
              <input formControlName="total"  readonly type="number" />
            </td>          
          </tr>
</form>

See that you can use this.addForm=this.createForm() and the Form have empty values. NOTA: I use "subtotal" (not "Subtotal") choose use lowercase or CamelCase to named the variables

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Todd
Solution 2 Eliseo