0

I have a Form In Angular-9 Application, contains few TextBoxes and My FormGroup object looks as below:

ngOnInit(): void {
  this.initForm();
  this.conditionalValidation();
}

initForm() {
    this.formCreateNewPlan = this.fb.group({
      channel: new FormControl('', { validators: [Validators.required], updateOn: 'blur' }),
      template: new FormControl('', { validators: [Validators.required], updateOn: 'blur', }),
      name: new FormControl('', {
        validators: [
          Validators.required, Validators.minLength(2), Validators.pattern(RegexPatterns.AlphaNumeric),], updateOn: 'blur'
      }),
      description: new FormControl('', {
        validators: [Validators.pattern(RegexPatterns.AlphaNumeric)], updateOn: 'blur'
      }),
      planBasis: new FormControl('', { validators: [Validators.required], updateOn: 'blur' }),
      startDate: new FormControl('', { validators: [Validators.required], updateOn: 'blur' }),
      endDate: new FormControl('', { validators: [Validators.required], updateOn: 'blur' }),
      circulation: [null],
      percentResponse: [null],
      orders: [null],
      units: [null],
      unitsPerOrder: [null],
      revenuePerOrder: [null],
      revenue: [null],
      unusualDemandRevenue: [null],
    });
  }

Also, I'm doing Conditional Validation as shown below:

conditionalValidation() {
    const circulation = this.formCreateNewPlan.get('circulation');
    const percentResponse = this.formCreateNewPlan.get('percentResponse');

    const orders = this.formCreateNewPlan.get('orders');
    const units = this.formCreateNewPlan.get('units');
    const unitsPerOrder = this.formCreateNewPlan.get('unitsPerOrder');
    const revenuePerOrder = this.formCreateNewPlan.get('revenuePerOrder');
    const revenue = this.formCreateNewPlan.get('revenue');
    const unusualDemandRevenue = this.formCreateNewPlan.get('unusualDemandRevenue');

    this.formCreateNewPlan.get('channel').valueChanges.subscribe(c => {
      if (c == "46") {
        circulation.setValidators([Validators.required, Validators.pattern(RegexPatterns.Numeric)]);
        percentResponse.setValidators([Validators.required, Validators.pattern(RegexPatterns.Numeric)]);
      } else {
        circulation.clearValidators();
        percentResponse.clearValidators();
      }

      if (c == "64") {
        orders.setValidators([Validators.required, Validators.pattern(RegexPatterns.Numeric)]);
        units.setValidators([Validators.required, Validators.pattern(RegexPatterns.Numeric)]);
        unitsPerOrder.setValidators([Validators.required, Validators.pattern(RegexPatterns.Decimal)]);
        revenuePerOrder.setValidators([Validators.required, Validators.pattern(RegexPatterns.Decimal)]);
        revenue.setValidators([Validators.required, Validators.pattern(RegexPatterns.Decimal)]);
        unusualDemandRevenue.setValidators([Validators.required, Validators.pattern(RegexPatterns.Decimal)]);
      } else {
        orders.clearValidators();
        units.clearValidators();
        unitsPerOrder.clearValidators();
        revenuePerOrder.clearValidators();
        revenue.clearValidators();
        unusualDemandRevenue.clearValidators();
      }

      circulation.updateValueAndValidity();
      percentResponse.updateValueAndValidity();

      orders.updateValueAndValidity();
      units.updateValueAndValidity();
      unitsPerOrder.updateValueAndValidity();
      revenuePerOrder.updateValueAndValidity();
      revenue.updateValueAndValidity();
      unusualDemandRevenue.updateValueAndValidity();
    });
  }

Here, I want to do some calculation based on TextBox values (on change):

  1. Orders – This is a calculated field when catalog is the channel (Circulation x Percent Response).
  2. Revenue - This is a calculated field (Orders x Revenue / Order).
  3. Units / Order – This is a calculated field (Units / Orders)

How to do this in Reactive Form? Please help me in this.

2 Answers 2

1

I prefer that you use (input) event on the form fields that you want to use their values to make the calculations.

i.e

.html

<input type="number" matInput (input)="calculateValues()" formControlName="circulation" />
<input type="number" [min]="0" [max]="100" matInput (input)="calculateValues()" formControlName="percentResponse" />

.ts

    calculateValues() {
      // check the fields required to make the calculations to avoid NaN errors
      if(this.formCreateNewPlan.value.circulation && this.formCreateNewPlan.value.circulation) {
        // patch the values on the form
        this.formCreateNewPlan.patchValue({
           orders: +this.formCreateNewPlan.value.circulation * +this.formCreateNewPlan.value.circulation
        });
      }
    }
Sign up to request clarification or add additional context in comments.

Comments

1

did you try setValue()?

orders.setValue(circulation.value * percentResponse.value); // using your consts here. Use this.formCreateNewPlan.get('orders').setValue() otherwise.

as FormGroups default to string, you might parseInt the values (dependent on whether your input is specified as type="number".

In order to toggle the calculation upon input change, you can either use the template (change)on the input itself, like:

// .html
<input formControlName="order" (change)="recalculateOrder()">

// .ts
public recalculateOrder() {
  this.formCreateNewPlan.get('orders').setValue(
    this.formCreateNewPlan.get('circulation').value *
    this.formCreateNewPlan.get('percentResponse').value
  );
}

or (ngModelChange) if you need the recalculation upon every keypress (I assume it is keyUp).

if you want to directly display the changed value, a changeDetectorRef.detectChanges() could be necessary. (injectable from angular/core)

btw a formCreateNewPlan.updateValueAndValidity() should do as stated in the docmentation

update value and validity documentation

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.