ARUN Madathil
ARUN Madathil

Reputation: 936

Angular reactive form not able to pass data to child component

im working with angular reactive form but having some issues while passing the formGroup data from parent to child component. here is the error that im getting

  [96msrc/app/invoice-form/invoice-form.component.html[0m:[93m3[0m:[93m103[0m
  • [91merror[0m[90m TS2740: [0mType 'AbstractControl' is missing the following properties from type 'FormGroup': controls, registerControl, addControl, removeControl, and 3 more.

[7m3[0m <app-form-item *ngFor = "let formItem of getInvoiceItem.controls; let i = index" [indexId] = "i" [invoiceFormItem] = "formItem" > [7m [0m [91m


 
[96msrc/app/invoice-form/invoice-form.component.ts[0m:[93m9[0m:[93m16[0m
    [7m9[0m   templateUrl: './invoice-form.component.html',
    [7m [0m [96m               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[0m
    Error occurs in the template of component InvoiceFormComponent. 

Parent Component

import { Component, OnInit } from '@angular/core';
    import { FormArray, FormControl, FormGroup } from '@angular/forms';
    import { FormItemComponent } from './form-item/form-item.component';
    
    

@Component({
  selector: 'app-invoice-form',
  templateUrl: './invoice-form.component.html',
  styleUrls: ['./invoice-form.component.css']
})
export class InvoiceFormComponent implements OnInit {

  public invoiceFormItems: FormGroup = new FormGroup({
    item:new FormControl(''),
    quantity:new FormControl(''),
    price:new FormControl(''),
    total:new FormControl(''),
  });
  constructor() { }

  ngOnInit(): void {
    this.createInvoiceItemForm();
  }

  public createInvoiceItemForm(): void 
  {
    this.invoiceFormItems = new FormGroup({
      items : new FormArray([
        FormItemComponent.addInvoiceItem(),
        FormItemComponent.addInvoiceItem(),
      ])
    });
  }
  get getInvoiceItem():FormArray {
    return this.invoiceFormItems?.get('items') as FormArray;
  }
  public submitInvoiceForm()
  {
  
  }

  public addNewInvoiceItems()
  {
    this.getInvoiceItem.push(FormItemComponent.addInvoiceItem());
  }
}

Parent Component html template

<form class="form " class="mt-2" autocomplete="off" [formGroup]="invoiceFormItems" (ngSubmit)="submitInvoiceForm()">

    <app-form-item *ngFor = "let formItem of getInvoiceItem.controls; let i = index" [indexId] = "i" [invoiceFormItem] = "formItem" >
      
    </app-form-item>
    
    <div class="form-group">
        <div class="col p-0">
            <button class="btn btn-primary" type="submit" (click)="addNewInvoiceItems()" [disabled]="!invoiceFormItems.valid"><i class="bx bx-plus"></i>
                Add
            </button>
        </div>
    </div>
    <button type="submit">Submit</button>
</form>

Child Component

import { Component, Input } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-form-item',
  templateUrl: './form-item.component.html',
  styleUrls: ['./form-item.component.css']
})
export class FormItemComponent {

  @Input() public invoiceFormItem: FormGroup = new FormGroup({
    item: new FormControl(''),
    quantity: new FormControl(''),
    price: new FormControl(''),
    total: new FormControl('')
  });

  constructor() { }
  static addInvoiceItem(): FormGroup {
    return new FormGroup({
      item: new FormControl(''),
      quantity: new FormControl(''),
      price: new FormControl(''),
      total: new FormControl('')
    });
  }
}

Child html template

<div [formGroup] = "invoiceFormItem"  >
<div class="mt-4">
  <div class="row justify-content-between">
    <div class="col-md-2 col-sm-12 form-group">
      <label for="item-name">Item</label>
      <input type="txt" class="form-control" id="item-name" name="item" formControlName="item" placeholder="Enter Item">
    </div>
    <div class="col-md-2 col-sm-12 form-group">
      <label for="quantity">Quantity</label>
      <input type="number" class="form-control" id="quantity"  name ="quantity" formControlName="quantity" placeholder="Enter Quantity">
    </div>
    <div class="col-md-2 col-sm-12 form-group">
      <label for="price">Price</label>
      <input type="number" class="form-control" id="price"  name ="price" formControlName="price" placeholder="Item Price">
    </div>
    <div class="col-md-2 col-sm-12 form-group">
      <label for="total">Total</label>
      <input type="number" class="form-control" id="total" name ="total" formControlName="total" placeholder="Item Total Amount">
    </div>
    <div class="col-md-2 col-sm-12 form-group d-flex align-items-center pt-4">
      <button class="btn btn-danger"  type="button"> <i class="fa fa-trash"></i>
      </button>
    </div>
  </div>
  <hr>
</div>  
</div>

The problem is I cant bind custom property to pass down the data(FormGroup) here

 <app-form-item *ngFor = "let formItem of getInvoiceItem.controls; let i = index" [invoiceFormItem] = "formItem" >
      
    </app-form-item>

Why is that error is occurring while binding the custom property for the child component, am i doing anything wrong? Any help will be really appreciated. Thanks

Upvotes: 0

Views: 912

Answers (1)

Eliseo
Eliseo

Reputation: 58099

Angular (really typescript) has no idea about your "formItem", the only is create a function like

getGroup(index){
  return (this.invoiceFormItems.get('items') as FormArray)
               .at(index) as FormGroup
}

An pass like

<app-form-item *ngFor = "let formItem of getInvoiceItem.controls; 
       let i = index" [indexId] = "i" [invoiceFormItem] = "getGroup(i)">

Upvotes: 1

Related Questions