Using TypeScript in Angular to make a function call can result in an endless loop being created

In my current use case, I am aiming to update the array in both the if and else scenarios.

The primary array, referred to as cis, appears as follows:

https://i.sstatic.net/esbb8.png

.html

<sample-container  [cis]="filterCi(currentBaseline.cis, currentBaseline)"> </sample-container>

.ts This particular function involves iterating over the provided array and returning a structure identical to the original, except for objects with the property checked:false being removed from the structure. This is achieved by recursively calling on children each time.

//retrieveChildren

retreiveChildren(children: Structure[]) : Structure[] {
  let filteredCis =  children && children.filter((ci) =>{
      if(ci.children && ci.children.length > 0){
         retreiveChildren(ci.children);
      }
      return ci.checked === true;
    }) ;
  return filteredCis;
}

//filterCi function

filterCi(cis: Structure[], baseline: Baseline): Structure[] {
    if(baseline.isHideElementsActivated){
      let newArray = [...cis]
      let result =  newArray.filter(ci => ci.checked === true).map((item,index) => {
        return {
          ...item,
          children : retreiveChildren(item.children)
        }
      })
      console.log("Result array...." , result)
      return result;
    }else{
      return cis;
    }
}

The challenge I am encountering here is that the filterCi function seems to be stuck in an infinite loop. Initially, I suspected it was due to the recursive call, but even after removing recursion, the issue persists.

Upon closer examination, I realized that the problem lies within the map function used inside filterCi. What causes this behavior, and what steps can I take to resolve it?

Answer №1

After implementing the solution for retreiveChildren, I tested it with the provided data and it successfully met my expectations.

I completely agree with @Jonathan's suggestion about not directly calling the filter function from the HTML. Using a Pipe, as suggested by him, would be the ideal approach.

However, during testing, I discovered a flaw in your current implementation. While the function effectively filters the parent nodes, it fails to impact the children nodes. To address this issue, you should assign the result of the recursive call to the children array in order to eliminate unchecked children.

Here is an updated snippet showcasing this idea:

retrieveChildren(children: Structure[]): Structure[]{
  const filteredCis = children && children.filter((ci) => {
    if (!ci.checked) {
      return false;
    }
    
    ci.children = retrievedChildren(ci.children);
    return true;
  });

  return filteredCis;
}

In my opinion, I made some improvements to enhance the readability of your function while refactoring it.

Answer №2

When a method is called from an input binding in a template, it gets evaluated on every change detection cycle because Angular cannot determine if it's a pure function (refer to this article for more information).

This might be the issue you're encountering. To fix this, you can use an Angular pipe: check out Angular pipes

Update: You can consider treating the transform method of the pipe as the filterCi method by creating a custom pipe:

// Custom Pipe
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filterCis'
})
export class FilterCisPipe implements PipeTransform {

  public transform(cis: Structure[], baseline: Baseline): Structure[] {
    if(baseline.isHideElementsActivated){
      let newArray = [...cis]
      let result =  newArray.filter(ci => ci.checked === true).map((item,index) => {
        return {
          ...item,
          children : retreiveChildren(item.children)
        }
      })
      console.log("Result array...." , result)
      return result;
    }else{
      return cis;
    }
  }

  private retreiveChildren(children: Structure[]) : Structure[] {
    let filteredCis =  children && children.filter((ci) =>{
        if(ci.children && ci.children.length > 0){
           retreiveChildren(ci.children);
        }
        return ci.checked === true;
      }) ;
    return filteredCis;
  }

}

After registering the pipe in the app module, use it in the template like this:

<sample-container  [cis]="currentBaseline.cis | filterCi:currentBaseline"> </sample-container>

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

Tips for leveraging multiple AWS Code Artifacts packages in a single project

Currently, I'm faced with a challenge while working on AWS CodeArtifact. My goal is to download three packages from the same domain. However, I have realized that I need to have three separate registries specified in my .npmrc file for each package in ...

When switching to compatibility view in IE 9, ASP.NET MVC 5 with Angular may cause the browser to crash

Upon deploying my site with MVC 5, Api 2 integrated with Angular and JQuery onto an intranet server, I encountered a strange issue. Due to internal policy restrictions, all sites on the intranet must operate under compatibility view. This caused a problem ...

How to locate and remove an object in Angular 6

What is the method to remove an object from a list of objects using an id number in Angular 6 with TypeScript? EntityService.ts import { Injectable } from '@angular/core'; import { Entity } from '../../models/entity'; @Injectable({ ...

Assign a specific value to the sub-component within the grid using Angular 2+

Incorporating Angular 8 and TypeScript into my project, I have a grid that consists of various internal components, one being <ng-select/>. The data binding takes place in the child component during onInit. Upon loading and initialization of the dat ...

The addControl function inside a for loop and async function is not properly assigning a value to the form

My goal is to iterate through an array, make a HTTP request, retrieve another array from it, and assign the selected object from the fetched array to a newly added Form Control in the form. This is how I approached it: for (let i = 0; i < typeaheadFiel ...

Challenge encountered while attempting to implement grid system in ionic framework

I'm completely new to the world of ionic framework, and I really need some assistance in completing this view. Please see the image reference https://i.stack.imgur.com/WOBFw.png I have made an attempt at it with the following code: <div class ...

Comparison between the version of a particular dependency and the version of its dependent dependency

Imagine a scenario where I have dependency X version 1.0 and dependency Y version 1.0 defined in my package.json. Would there be any issues if Y requires X version 2.0 (as indicated in the package-lock.json) but I continue to use X version 1.0 in my code ...

An issue has occurred: The function _co.deleteConsulta is not recognized as a valid function

While following a tutorial on creating a CRUD application using Firestore, I encountered an issue when trying to delete data from Firestore. Every time I attempt to delete a user from my Firestore database, I receive an error stating that ._co.deleteConsul ...

Angular Code Splitting with Webpack

My current project setup is causing some loading issues due to the large download size of Angular Material. As a result, a white screen remains loading for around 45 seconds. I have attempted to implement code splitting to enhance the loading speed of my a ...

What is the reason for not being able to retrieve params in resolve functions?

When creating a show page, I encountered an issue with ensuring the data is available before displaying the page. Traditionally, I would use the resolve property in a route to achieve this, but with ui-router, I do not have access to attributes in $state ...

What is the best way to calculate checksum and convert it to a 64-bit value using Javascript for handling extremely large files to avoid RAM overflow?

Question: What is the best method for generating a unique and consistent checksum across all browsers? Additionally, how can a SHA256/MD5 checksum string be converted to 64-bit? How can files be read without requiring excessive amounts of RAM when ...

Why does TypeScript not recognize deconstructed arrays as potentially undefined variables?

When looking at the code snippet below, I was under the impression that the destructured array variables, firstName and lastName, would be classified as string | undefined. This is because the array being destructured could have fewer variables compared ...

Angular sending information from one page and retrieving it on another

The reportForm page allows users to input information and submit it to create a report. reportData = { headline: $scope.headline, fromDate: $scope.fldFromDate, toDate: $scope.fldToDate, whatever: $scope.whatever } $http.post(reportUrl + $scope.repor ...

Switch up text colors on the fly in Angular as you type!

I've been developing a Note Taking application where users can type in red text. Additionally, they should also have the ability to change the color of the remaining text to black while typing. ...

How do I fix the build error that says "Operator '+' cannot be used with types 'number[]'?

The function below is designed to generate unique uuidv4 strings. function uuidv4() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => ( c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)) ...

When utilizing Typescript with React Reduxjs toolkit, there seems to be an issue with reading the state in useSelector. An error message is displayed indicating that the variable loggedIn

I have encountered an error while passing a state from the store.tsx file to the component. The issue lies in the const loggedIn where state.loggedIn.loggedIn is not recognized as a boolean value. Below is the code snippet for the component: import React ...

Tips for populating fields with constant data and clearing sections upon clicking with angular2

I have defined emergency as static data in TypeScript. Now, I want to populate this static data into two sections. Can someone please advise me on how to achieve this or provide relevant links? I am still learning about reactive forms so any help would be ...

Angular 4's Panel Window: A User-Friendly Interface

Having experience with Adobe Flex, I am familiar with creating new panel windows in Action Script by using the 'new' keyword and popping them up using popups. The customization of these windows was achieved through functions provided in the Panel ...

In HTML, data can be easily accessed, however, JavaScript does not have the same

When trying to access the 'data' element in a JSON object, I have encountered an issue. The element is accessible when called from HTML, but not when called in JavaScript. HTML: <p>{{geoJson.data}}</p> JavaScript: let scope; let d ...

Enhancing Angular Form Control with ASP.NET Core 7 Web API Date Serialization

The Person class has a property called Birthday, which is defined as type DateTime. public class Person { public string Name { get; set; } public DateTime Birthday { get; set; } } Within my controller, I have an endpoint setup like this: [HttpGet( ...