4

I'm trying to build an Angular reactive form in which inputs field values are updated based on inputs in other fields. Three input fields amount, price and total are supposed to reflect changes so that amount * price = total holds. Full code https://stackblitz.com/edit/angular-e7rnxf

import {
  Component,
  Input
} from '@angular/core';
import {
  FormBuilder
} from '@angular/forms';
@Component({
  selector: 'hello',
  template: `
  <form [formGroup]="orderForm" (ngSubmit)="onSubmit()">  
    Amount: <input (keyup)="onAmountChange($event)" formControlName="amount">{{ orderForm.value.amount }}<br>
    Price: <input (keyup)="onPriceChange($event)" formControlName="price">{{ orderForm.value.price }}<br>
    Total: <input (keyup)="onTotalChange($event)" formControlName="total"> {{ orderForm.value.total }}<br>
    <button type="submit">Submit</button>
 </form>
  `
})
export class HelloComponent {
  constructor(private fb: FormBuilder) {}
  orderForm = this.fb.group({
    amount: 200,
    price: 95,
    total: ''
  });
  onTotalChange(e) {
    const total = e.currentTarget.value;
    this.orderForm.value.amount = total / this.orderForm.value.price;
  }
  onAmountChange(e) {
    const amount = e.currentTarget.value;
    this.orderForm.value.total = this.orderForm.value.amount * this.orderForm.value.price;
  }
  onPriceChange(e) {
    const price = e.currentTarget.value;
    this.orderForm.value.total = price * this.orderForm.value.amount;
  }
  onSubmit() {
    console.log(this.orderForm.value);
  }
}

3
  • this.orderForm.value is read only thats why you can not overwrite Commented Mar 26, 2019 at 23:13
  • 2
    instead of all the (keyup)s, simply subscribe to this.orderForm.valueChanges. It's a good idea to read at least the documentation's first page Commented Mar 26, 2019 at 23:29
  • That's a statement of fact, not a question. Commented Mar 26, 2019 at 23:42

3 Answers 3

3

this.orderForm.value is read only. then you can Try by doing something like this

this.orderForm.controls['total'].setValue(price/ this.orderForm.value.amount);

stackblitz example modified

Sign up to request clarification or add additional context in comments.

Comments

2

Im unsure how to fork stackblitz but if you replace your class with the following you will get the correct result.

import { FormBuilder, FormGroup } from '@angular/forms';


export class HelloComponent implements OnInit  {
  constructor(private fb: FormBuilder) {}

  public orderForm: FormGroup;

  public ngOnInit(): void
  {
    this.orderForm = this.fb.group({
      amount: 200,
      price: 95,
      total: ''
    });
  }

  onSubmit() {
    const amount = this.orderForm.controls.amount.value;
    const price = this.orderForm.controls.price.value;

    this.orderForm.controls.total.setValue(amount * price);
  }
}

This will give you the total on submit, to have the value changing as the other inputs do, you could re add the functions as they were but now instead looking to use this.orderForm. When ever a change is made to one of the input fields, you can check its value with this.orderForm.controls.price.value or this.orderForm.controls.price.value. Or you could just console.log(this.orderForm.value); to get all three values as an object. Which would look like {amount: 200, price: "97", total: 19400}.

Comments

1

I notice that the above answers offer the solutions of using setValue, which is more than enough, in this given scenario. However, I would like you to know that you can make use of patchValue too.

For instance, if you would like to only update the value of total (and not other FormControls) on your reactive form, you can simply achieve that by doing this:

this.orderForm.patchValue({
  total: price * this.amount
});

As you can see, the syntax is simpler and much more intuitive. On the other hand, if you try to achieve that with setValue, you will have to explicitly chain it, or you have to update all the FormControls due to the limitations of setValue and the way that method works. If you do not supply all the FormControls, it will throw an error. This may not be a bad thing, as it is 'safer'.

this.orderForm.setValue({
  amount: 200,
  price: 95,
  total: price * this.amount
}) 

Comments

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.