0

i have a form that contains a formArray (FinYearArray) that on his turn contains another formArray (RecipientArray) both these FinYearArray and RecipientArray contains a formControl for the amount, everytime there is a change on these fields the total should be calculated for the financial years and for the recipient countries by financial year. For the total of the recipients i created a formControl in the FinYearArray named 'RecipientTotal'

//structure of the form
{
    "FinYearArray": [
        {
            "FinYear": 2022,
            "FinYearAmount": 0,
            "RecipientTotal": 0,
            "RecipientArray": [
                {
                    "CtryDesc": "",
                    "Amount": 0,
                },
                {
                    "CtryDesc": "",
                    "Amount": 0,
                }
            ],
        },
        {
            "FinYear": 2023,
            "FinYearAmount": 0,
            "RecipientTotal": 0,
            "RecipientArray": [
                {
                    "CtryDesc": "",
                    "Amount": 0,
                }
            ],
        }
     ],
    "ProjectCode": "",
}

in my ngOnInit() i have this code to check when there are changes in the FinYearArray formArray and automaticcaly also in the RecipientArray formArray because it is inside the other formArray

//function that calculates the totals for fin year and recipients/fin year

    this.formDetailReport.get('FinYearArray').valueChanges.subscribe(values => {
        this.myFinYearTotal = 0;
        const ctrl = <FormArray>this.formDetailReport.controls['FinYearArray'];

    //loop trough fin years
        ctrl.controls.forEach(x => {
            let parsed = Number(x.get('FinYearAmount').value);
            this.myFinYearTotal += parsed;
        });

//loop through recipient countries for each financial year
            for (let i = 0; i < ctrl.controls.length; i++) {
                this.myRecipientTotal = 0;
                const recipientFormArray = <FormArray>ctrl.controls[i].get('RecipientArray');

                recipientFormArray.controls.forEach(x => {
                    let parsed = Number(x.get('Amount').value);
                    this.myRecipientTotal += parsed;
                });
                console.log('total : ' + i + ' amount : ' + this.myRecipientTotal );
// when using this code i get the error at the end of this mail
                this.formDetailReport.controls['cFinYearGroup']['controls'][i].controls.cRecipientTotal.setValue(this.myRecipientTotal);
                // ctrl[i].controls.cRecipientTotal.setValue(this.myRecipientTotal);
            }
            this.ref.detectChanges();
        });

but i get this error

// error when i try to assign the calculate value to the formControl
core.js:4442 ERROR RangeError: Maximum call stack size exceeded
    at EuiInputNumberComponent.ngDoCheck (eui-components-next.js:11713:1)
    at callHook (core.js:3285:1)
    at callHooks (core.js:3251:1)
    at executeInitAndCheckHooks (core.js:3203:1)
    at refreshView (core.js:7395:1)
    at refreshEmbeddedViews (core.js:8481:1)
    at refreshView (core.js:7404:1)
    at refreshComponent (core.js:8527:1)
    at refreshChildComponents (core.js:7186:1)
    at refreshView (core.js:7430:1)

i think this comes because every time i update the recipient total (cRecipientTotal formControl) this piece of code is re-executed because there is a valueChange inside the formArray

isn't there a way that this valueChange is only watching the FinYearAmount formControl inside the formArray instead of watching all the fields of this formArray? and afterwords watching the formcontrol Amount in the RecipientArray

1 Answer 1

2

When updating an AbstractControl which has a valueChanges listener attached and you don't want to retrigger it (causing the infinite loop you are suffering from), you can add a configuration object to your setValue/patchValue call:

myFormControl.setValue(value, { emitEvent: false });
Sign up to request clarification or add additional context in comments.

3 Comments

when using this emitEvent like this this.formDetailReport.controls['cFinYearGroup']['controls'][i].controls.cRecipientTotal.setValue(this.myRecipientTotal, { emitEvent: false }); still gives an Maximum call stack size exceeded error or do i use it not correctly?
That looks correct. Try adding { onlySelf: true } to the config object. You've got an infinite loop happening somewhere.
Thanks for this answer. I am struggling the infinite loop for weeks!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.