Avoiding infinite digest loops caused by ng-model with getterSetter in AngularJS

Check out this HTML snippet:

<select style="width: 100%;" ng-model="vm.orgType" ng-model-options="{getterSetter: true}" ng-options="orgType as orgType.ORGANIZATION_TYPE for orgType in vm.orgTypes">
</select>

Now, let's take a look at the getter/setter function:

function orgType(selectedType) {
    if (arguments.length == 0)
        return orgType.selectedOrgType || { ORGANIZATION_TYPE: 'Organization Type', ORGANIZATION_TYPE_ID: null };

    orgType.selectedOrgType = selectedType;
    if (selectedType.ORGANIZATION_TYPE_ID) {
        if (vm.registrant.StakeholderOrgs[0])
            vm.registrant.StakeholderOrgs[0] = selectedType.ORGANIZATION_TYPE_ID;
        else
            vm.registrant.StakeholderOrgs.push(selectedType.ORGANIZATION_TYPE_ID);
    } else
        vm.registrant.StakeholderOrgs.splice(0);
}

This specific line of code is causing an infinite digest loop error:

return orgType.selectedOrgType || { ORGANIZATION_TYPE: 'Organization Type', ORGANIZATION_TYPE_ID: null };

Allow me to explain my intention with this setup. I aim to add the ID to a list upon making a selection. While I could simply use an ng-model on a variable like selectedOrgType and handle logic in an ng-change, I prefer structuring a dropdown without creating extra model variables. My approach involves utilizing a getter/setter for more streamlined functionality. Despite setting one of vm.orgTypes to

{ ORGANIZATION_TYPE: 'Organization Type', ORGANIZATION_TYPE_ID: null }
as the default value, I encountered the unexpected digest error and am puzzled by its origin.

Answer №1

By including the ng-model attribute, Angular automatically adds an internal watch that checks the value on every digest loop. If the value changes, it triggers another digest cycle.

In your situation, you are returning an object literal. In JavaScript, when comparing two literals with the same structure, they will evaluate to false:

({a:1} == {a:1}) // false

This is because they are actually two different objects.

Therefore, when you return an object literal in your getter, the watch compares it to the previous value and since it's a new object each time, it results in false.

This leads to the error of infinite digest loops.

To resolve this issue, simply return the same object:

If you have an object inside an array like:

vm.orgTypes=[
    { ORGANIZATION_TYPE: 'Organization Type', ORGANIZATION_TYPE_ID: null }
];

You can directly use it:

return orgType.selectedOrgType || orgTypes[0];

Another approach is to save the default value to a variable and utilize it:

var defaultSelect = { ORGANIZATION_TYPE: 'Organization Type', ORGANIZATION_TYPE_ID: null };

....

function orgType(selectedType) {
    if (arguments.length == 0)
        return orgType.selectedOrgType || defaultSelect;

By doing this, you ensure that you return the same element in the default scenario, thus avoiding infinite digest cycles.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

ng-click="showInventory()" onClick="currentTemplate='/inventory.html'" Not

I'm facing an issue with my menu list. When I apply the ng-repeat directive, it seems to not work properly. However, when I remove the ng-repeat, everything functions as expected. <div class="reports_header_tabs_holder"> <span ng-repea ...

What is the process for conducting linting with nodemon?

Is it possible to utilize nodemon for linting my javascript without the use of build tools like gulp or grunt, in order to fully leverage node and npm? Nodemon's output can be piped. I am interested in using this feature for linting the changed file ...

Creating a grid UI in AngularJS using Typescript: utilizing functions as column values

I am working on an AngularJS app that includes the following UI grid: this.resultGrid = { enableRowSelection: true, enableRowHeaderSelection: false, enableHorizontalScrollbar: 0, enableSorting: true, columnDefs: [ { name: &apos ...

Dealing with Buffer data received from a NextJS backend API

In my NextJS application, one of the backend API routes returns a JSON object that includes a buffer. // The nodeConfiguration contains a buffer for the nodeId property res.status(200).json(nodeConfiguration); However, when trying to display the nodeId va ...

What type of Javascript is required for a photo carousel that displays random images from a designated folder?

I have a minor issue that has been keeping me up at night. I can't seem to shake it off and find the right solution! Currently, I am working with Bootstrap 4 as my Framework. My task is to create a full-page Carousel that cycles through images random ...

Using the ref callback to access getBoundingClientRect values in React Components

I'm having some trouble extracting data using the getBoundingClientRect() method from a set of animated div elements. The issue I'm facing is that the refCallback function is returning empty DOMRect objects. If you're interested, feel free t ...

Retrieve Next Element with XPath

I recently started working with XPATH and have a few questions about its capabilities and whether it can achieve what I need. The XML Document structure I am dealing with is as follows: <root> <top id="1"> <item id="1"> < ...

Trouble with triggering Ajax file upload progress event

Using AJAX request, I am splitting and uploading a file in chunks. However, I have encountered an issue with the progress event not firing in Firefox. Below is the relevant code snippet: //slice file if(file.mozSlice){ chunk = file.mozSlice(startByt ...

Maintain the previous droppable positioning after refreshing the page

I am encountering an issue with the .droppable event. I have set up two sections where I can move elements, but every time the page is refreshed, the positioning of the elements reverts to the initial position. How can I maintain the last positioning of th ...

Issue arises where multiple asynchronous functions cause infinite re-rendering due to the shared loading state

Currently, I am integrating zustand 4.1.5 into my React application. Upon clicking the LogDetails tab, two asynchronous functions with identical loading state settings are triggered simultaneously, leading to an endless rerendering cycle and causing the & ...

update the variables based on the changes in the service

I have developed a service in my application to retrieve configuration settings from the database. This service is used to display various configurations across different parts of the app. However, I am encountering an issue where the variables do not upda ...

What causes my useEffect hook to trigger twice in React?

I'm currently utilizing @preact/signals-react in my react project for integration purposes. Encountered a challenge that requires resolution. Interestingly, I discovered that by removing import { signal } from '@preact/signals-react', the ...

What is the best way to create an index for a user-provided value in a textbox

Looking for guidance on how to set an index to user-provided values in a textbox, append them to a table in a new row, and display that index in the first column of every row. I am unfamiliar with this type of functionality. $(document).ready(function() ...

Tips for recognizing the click, such as determining which specific button was pressed

Currently, I am utilizing Angular 6. On the customer list page, there are three buttons - "NEW", "EDIT", and "VIEW" - all of which render to one component. As a result, it is crucial for me to determine which specific button has been clicked in order to ...

Indexing text fields for MongoDB collection that have been populated

Currently, I am in the process of learning how to use indexing with Mongoose/MongoDB and I am facing an issue that I can't seem to resolve. This is the schema I am working with: const timeSchema = new mongoose.Schema({ actionId:{ type:St ...

The AudioPlayer refuses to play following a track change

I am looking to implement an audio player in React Nextjs that features interactive dots, each representing an audio track. The functionality I want is such that clicking on a dot will pause the currently playing track (if any) and start playing the select ...

The functionality of a button within an AngularJS directive is not functioning as intended

I am trying to use a directive twice on one page. Inside the directive, there is a button that should toggle between showing the two directives when clicked. However, I'm encountering an issue where the values are not changing even though the ng-click ...

To prevent the animation from overflowing, set the parent element to have hidden overflow while still displaying the child element

I am facing an issue with two menus that can be toggled using a switch. Each menu item has a dropdown that appears when clicked. The problem arises when switching between the menus, as there is an animation for the transition (slide in and slide out). I wa ...

Generating Tree Structure Object Automatically from Collection using Keys

I am looking to automatically generate a complex Tree structure from a set of objects, with the levels of the tree determined by a list of keys. For example, my collection could consist of items like [{a_id: '1', a_name: '1-name', b_id ...

The directive binding value is accurate, however it is failing to return a true result

The behavior of a custom directive is puzzling me. When I directly pass in a value, it works fine. However, if I bind the value to a variable, it doesn't work as expected. Interestingly, when I use console.log to show the value, it appears to be corre ...