简体   繁体   中英

How to do calculation for two form fields in angular and patch it

[ReferenceImage][1]

->Hello, I need to do the calculation for two fields look at the reference image once.

->In the basic pay field if I enter 100 and in Gst % on the first premium amount if I enter 5 then automatically in the first premium amount 105 value should display calculation is like (100+5%100 = 105).

->same if I enter 5 in GST % on next premium amount 105 should be displayed in the next premium amount field. [1]: https://i.stack.imgur.com/KNtAa.png

if you are using angular reactive forms, you can use the patchValue() method of the FormGroup.

You can refer the document link: Angular document for reactive forms

In your case you can call the patchValue method onKeyPress.

It's a problem very common to have a form with some "calculated value".

In Angular we has two aproach to mannage forms: Reactive Forms (the formGroup and FormControl) or Template driven form (the [(ngModel)])

If we use [(ngModel)] we can store the calculate value in a variable (or not). If we use FormGroup we can store the calculate value in a FormControl of the FormGroup or not. Really it's unnecessary store the value calculate. We can make, eg

<form #f="ngForm">
  <input name="cant" [(ngModel)]="cant" />
  <input name="porc" [(ngModel)]="porc" />
  <input name="result" readonly [ngModel]="(+cant * +porc) / 100" />
</form>
{{f.value|json}} <---just to check


//in .ts
cant:number=0;
porc:number=0;

or

<form [formGroup]="form">
  <input formControlName="cant">
  <input formControlName="porc">
  <input readonly [ngModel]="+form.value.cant*(+form.value.porc)/100" 
                  [ngModelOptions]="{standalone:true}">
</form>
{{form?.value|json}} <--just to check

//in .ts
  form=new FormGroup({
    cant:new FormControl(0),
    porc:new FormControl(0)
  })

See that always need convert to number the "values". It's the reason to add the + to the values. See also that the only code in.ts is declare the variables or declare the formGroup

I use a input readonly, but you can use a span or a div

Well, if we want to store the result in a variable -or in a FormControl of the formGroup we need make some changes

<form #f="ngForm">
    <input name="cant" [ngModel]="cant" 
         (ngModelChange)="cant=+$event;calculateResult()" />
    <input name="porc" [(ngModel)]="porc" 
         (ngModelChange)="porc=+$event;calculateResult()"/>
    <input name="result" readonly [ngModel]="result" />
</form>
{{f.value|json}}

//in .ts
//add a new variable
result:number=0
//and add the function calculateResult
calculateResult(){
   this.result=this.cant*this.porc/100
}

See how "split" the [(ngModel)] in [ngModel] and (ngModelChange).

Using reactive form

<form [formGroup]="form">
  <input formControlName="cant" (input)="calculateResultForm()" />
  <input formControlName="porc" (input)="calculateResultForm()"/>
  <input readonly formControlName="result" />
  />
</form>

//in .ts
  form=new FormGroup({
    cant:new FormControl(0),
    porc:new FormControl(0),
    result:new FormControl(0) //<--we add this FormControl
  })
  //and the function
  calculateResultForm()
  {
    this.form.get('result').setValue(
         +this.form.value.cant*(+this.form.value.porc)/100)
  }

Well, in reactiveForms is common use the observable valueChanges instead of using the event input. valueChanges are an observable. This mean that you can subscribe to changes (in ngOnInit). eg we can do

ngOnInit(){
    this.form.get('cant').valueChanges.subscribe((res:any)=>{
      this.calculateResultForm()
   })
   this.form.get('porc').valueChanges.subscribe((res:any)=>{
      this.calculateResultForm()
   })
}

  calculateResultForm()
  {
    //see that in this case we can NOT use
    //this.form.value.cant and this.form.value.porc
    //because the value is with the old values

    const cant=+this.form.get('cant').value
    const porc=+this.form.get('porc').value
    this.form.get('result').setValue(cant*porc/100)
  }

Well the "problem" with the observables is that we need unsubscribe in ngDestroy of the component, so we declare two variables

   sub1:Subscription
   sub2:Subcription

When use the valueChanges we use

    this.sub1=this.form.get('cant').valueChanges.subscribe((res:any)=>{
      this.calculateResultForm()
   })
   this.sub2=this.form.get('porc').valueChanges.subscribe((res:any)=>{
      this.calculateResultForm()
   })

And in ngOnDestroy we write

  ngOnDestroy(){
    this.sub1.unsubscribe()
    this.sub2.unsubscribe()
  }

Well really nobody subscribe each FormControl, generally we use an rxjs operator to create an unique subcription.

We can use rxjs operator merge . don't worry it's only put the values changes separated by commas

    this.sub1=merge(
      this.form.get('cant').valueChanges,
      this.form.get('porc').valueChanges
    ).subscribe((res:any)=>{
      this.calculateResultForm()
   })

Others ways are use forkJoin or similar, use takeUntil or takeWhile to unsubscribe automatically, etc. but this answer is yet a bit large

NOTE: I know that the first time you meet ReactiveForms and Observables scare a few. Really they are a powerful tool and we need understand a bit about they

If you get the final of the answer, great,, you can check the stackblitz

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM