typescriptangular12core-js

Angular 12 Infinite Refresh in core.js


We have a donation system built on Angular 12 with a C# backend. This issue has arisen because we are designing the site. The current site works. The redesign has caused an issue where under certain circumstances the site can get stuck in an infinite loop in the core.js refreshView method. I know this because after 30 seconds or so when I hit the pause button in Visual Studio, the call stack shows repeated calls to this method and the console.log statements show repeated looping of a single dropdown's list of items, more on that later.

There are a number of components that needed to access the cart session. To keep each component from making a call to the database we used BehaviorSubject to emit the data to each component. The component in question is used to both allow user to search/select a fund and also edit the fund from the side cart component. Some of the funds have advanced options (classes), some do not. The funds that have advanced options are populated when the user selects the fund. This process typically populates a dropdown with a normal ngFor. This must be a dynamic process as each fund can have different classes, etc. The search/select functionality is working with no problems. Users can add those funds to the cart, no issues there.

However, when a user attempts to edit a cart item an that item has classes, the page gets stuck in a infinite loop eventually ending with the browser asking the user if they want to wait or exit, etc.

What I discovered during my research was during the search/selection process when we populate the dropdown, the list was being looped over 12 times even though the displayed list only contained the seven items we expected. This is not enough to cause a page lock up. After testing I determined the same issue exists on the current production site. But because the search component is not the same as the edit component in production, we never had this come up.

When the user attempts to edit these items the console.log statements continually display in the browser console. Any item in the cart that does not have classes, display as expected and do not lock up the page.

What we've tried. AI has suggested this is a change detection issue, but the suggested solutions have not helped.

What we have not tried yet.


Solution

  • The cause of the looping was coming from the parent element of the select/ngFor — accordion-group and its Angular event (isOpenChange). It appears this is what was triggering the change detection.

    <accordion-group #group [isOpen]="showAdvancedGivingOptions" (isOpenChange)="toggleAdvancedGivingOptions()">
        <span accordion-heading>
            Advanced Options <i class="fa-solid fa-caret-down"></i>
        </span>
        <select class="full-width add-top-margin" formControlName="selectItemDropdown" (change)="onItemSelectChange()" [compareWith]="objectCompareFunction">
            <ng-container *ngFor="let f of itemList">
                <option *ngIf="isDescriptionValid(f.preferredDescription) || f.isDefault" [ngValue]="f">
                    {{ f.preferredDescription }}
                </option>
            </ng-container>
        </select>
    </accordion-group>
    

    The toggleAdvancedGivingOptions method is very simple and just toggles a Boolean value.

    this.showAdvancedGivingOptions = !this.showAdvancedGivingOptions;
    

    The solution was to add a parameter to toggleAdvancedGivingOptions method.

    The accordian-group tag changes to this.

    <accordion-group #group [isOpen]="showAdvancedGivingOptions" (isOpenChange)="toggleAdvancedGivingOptions($event)">
    

    And the toggleAdvancedGivingOptions method change to this.

    toggleAdvancedGivingOptions(newValue: boolean) {
      if (this.showAdvancedGivingOptions !== newValue) {
        this.showAdvancedGivingOptions = newValue;
      }
    }
    

    We still get more looping than I would like, but the looping does stop and the page no longer locks up.