0

I'm using reactive forms in Angular and i have this FormArray from which i am getting all value except product_total.

<tbody formArrayName="products">
  <tr *ngFor="let phone of productForms.controls; let i=index" [formGroupName]="i">
      <th scope="row">{{i+1}}</th>
      <td><input type="text" class="form-control" placeholder="Product Code" formControlName="product_code"></td>
      <td><input type="text" class="form-control" placeholder="Product Name" formControlName="product_name"></td>
      <td><input type="number" class="form-control" placeholder="Price" formControlName="product_price" #price></td>
      <td><input type="number" class="form-control"  formControlName="product_quantity" value="1" #quantity></td>
      <td><input type="number" class="form-control" value="{{(price.value || 0) * (quantity.value || 1)}}" formControlName="product_total" disabled></td>
    </tr>
  </tbody>

How to get product_total value for each formgroup inside the typescript code? P.S. I'm getting the value inside the HTML Code but not in the typescript code

The typescript code is:

constructor(private fb: FormBuilder) { }

ngOnInit() {
const product = this.fb.group({
  product_code: [],
  product_name: [],
  product_price: [],
  product_quantity: [1],
  product_total: []
});

this.myForm = this.fb.group({
  customer_name: '',
  customer_phone: '',
  customer_address: '',
  products: this.fb.array([product]),
  subtotal: Number,
  discount: Number,
  cgst: Number,
  sgst: Number,
  total_price: Number,
});
}

get productForms() {
  return this.myForm.get('products') as FormArray;
}


async submitForm() {
    const myForm = this.myForm.value;
    this.invoice = {
      products: myForm.products,
    };
    console.log(this.invoice.products);

  }
7
  • If you want a total of all, you must subscribe to valueChanges, see e.g. alligator.io/angular/reactive-forms-valuechanges. If only a total by line use {{phone.get('product_price').value *( phone.get('product_quantity').value ||1)}} Commented Aug 1, 2018 at 10:36
  • @Eliseo this is not what i was asking. I'm getting the product_total value inside the form input but not in the typescript code. In typescript code i'm getting null. Commented Aug 1, 2018 at 10:41
  • show full line of code Commented Aug 1, 2018 at 11:05
  • @SurendraSinghChhabra, see my answer Commented Aug 1, 2018 at 11:38
  • @SurendraSinghChhabra can you add typescript of this component? Commented Aug 1, 2018 at 11:47

2 Answers 2

2

Edited, the before code has {{ }}, but if we using [value] you needn't put {{ }}, updated the code

You need'nt the total belong to the formGroup

<input type="number" class="form-control" disabled
    [value]="phone.get('product_price').value *( phone.get('product_quantity').value)" >

in submit you can make a map if you consider necessary

submit(form){
   if (form.valid)
   {
      let data={
             //all properties of for.value
             ...form.value,
             //but products was products "mappeated"
             products:form.value.products.map(v=>{
             return {
               //Which each product, return 
               ...v,   //all de properties of products +
               total:v.product_price*v.product_quantity  //total
          }})
        }

      console.log(data);
   }
Sign up to request clarification or add additional context in comments.

5 Comments

mapping is working but not getting the data in array. i.e. getting the data in console but not in array
@SurendraSinghChhabra, sorry. I wrote [value]="{{...}}" and was [value]="..." (not enclosed by {{ }} ). My idea is that the formGroup NOT have "total". If we need total to send to an api or whatever, we always can, in submit the form create the property total
Got that! but still not working. Please see the typescript code that i updated for more reference. Also the {...v,total:vproduct_priceproduct_quantity} is not defined as it is in form array so that is also giving error.
@SurendraSinghChhabra, yet update the code, sorry for delay
Working!! Thanks for your efforts.
0

I had a similar piece of logic to implement. I did it in the controller using something like this:

ngOnInit() {
    this.formGroup = this.formBuilder.group({
        price: ['', [Validators.required]],
        quantity: ['', [Validators.required]],
        total: ''
    });

    this.formGroup.valueChanges.subscribe(change => {
        this.priceChanges()
    })
}

priceChanges() {
    let price = parseFloat(this.formGroup.value.price);
    let quantity = parseInt(this.formGroup.value.quantity);

    if (!isNaN(price) && !isNaN(quantity)) {
        let totalCost = (price * quantity).toFixed(2);
        this.formGroup.controls['total'].setValue(totalCost, { emitEvent: false })
    }
}

Edited version to handle FormArray:

Note the added (ngModelChange)="detectValueChange(i)" on two of your inputs:

<tbody formArrayName="products">
    <tr *ngFor="let phone of productForms.controls; let i=index" [formGroupName]="i">
        <th scope="row">{{i+1}}</th>
        <td> <input type="text" class="form-control" placeholder="Product Code" formControlName="product_code"></td>
        <td> <input type="text" class="form-control" placeholder="Product Name" formControlName="product_name"></td>
        <td><input type="number" class="form-control" placeholder="Price" formControlName="product_price" #price (ngModelChange)="detectValueChange(i)"></td>
        <td><input type="number" class="form-control" formControlName="product_quantity" value="1" #quantity (ngModelChange)="detectValueChange(i)"></td>
        <td><input type="number" class="form-control" value="{{(price.value || 0) * (quantity.value || 1)}}" formControlName="product_total" disabled></td>
    </tr>
</tbody>

Then, similar to my original solution, but now with indexing on the 'products' array

detectValueChange(index: number){
    let controls = this.formGroup.get('products') as FormArray;
    this.changeTotal(controls[index])
}

changeTotal(control) {
    let price = parseFloat(control.value.product_price);
    let quantity = parseInt(control.value.product_quantity);
    if (!isNaN(price) && !isNaN(quantity)) {
        let totalCost = (price * quantity).toFixed(2);
        control['product_total'].setValue(totalCost, { emitEvent: false })
    }
}

5 Comments

be carefull, 1.- your function priceChanges is wrong. You must use this.formGroup.get('price').value, NOT this.formGroup.value.price -see in console the diference. 2.- as you attach the change to all changes in the form, when change the "total", go to the function again
You're completely correct! I forgot to add { emitEvent: false }, see edited version.
using this approach leads to getting total only in first formgroup not in others
@SurendraSinghChhabra Didn't notice the FormArray. See my edited answer (not tested!). toFixed will give you a string, so might want to wrap that in parseFloat.
@SurendraSinghChhabra You could also work something by using [formControlName] to reach the nested FormControl. See this answer: stackoverflow.com/a/48151444/4632627

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.