Continuously verify if there are any active child elements

I am dealing with a recursive list of items in Angular/TypeScript. My goal is to only show items when they are either active=true; themselves or if any of their children or grandchildren are also active=true.

data.json

[
    {
        "active": true,     
        "items": [
            {
                "active": false,    
                "items": [
                    {
                        "active": false,
                        "items": []
                    },
                    {
                        "active": false,
                        "items": []
                    }
                ]
            },
            {
                "active": false,    
                "items": [
                    {
                        "active": true,
                        "items": []
                    }
                ]
            },
            {
                "active": true,    
                "items": [
                    {
                        "active": true,
                        "items": []
                    }
                ]
            }
        ]
    }
]

Despite my current recursive method, it still does not handle nested items and incorrectly returns false for all parents when I set the deepest item as active=false;

The issue arises from the fact that when an item had children, the recursion would simply continue (

return this.hasActiveChildren(i);
) without considering the current item.active status.

method.ts

  public hasActiveChildren(item: Item): boolean {
    if (item.items === null || item.items.length <= 0) {
      return false;
    }

    return item.items.some(i => {
      if (i.items === null || i.items.length <= 0) {
        return i.active;
      } else {
        return this.hasActiveChildren(i);
      }
    });
  }

A second method performs better by returning false for a parent if all immediate children are active=false;. Nonetheless, it still overlooks the children´s children.

updatedMethod.ts

  public hasActiveChildren(item: Item): boolean {
    for (const i of item.items) {
      if (i.active === true) {
        return true;
      } else if(i.items=== null || i.items.length <= 0) {
        return this.hasActiveChildren(i);
      }
    }

    return false;
  }

I might need to specify:

  • I have a recursive list of items with an unknown depth
  • Each item possesses an active property
  • I aim to develop a method that yields true when any children or children´s children's active property is set to true
  • Two methods have been created to address this issue, but neither fully solves it

Answer №1

Your current method of checking if the children are active only when the parent is not active may lead to issues. It's best to recursively check the children every time or before determining the status of the parent. I've utilized the following model:

interface Item {
    isActive: boolean,
    subItems: Item[]
}

Below is an approach using the filter function, which will call the function for each child item before returning an array of all actively displayed items within item.subItems. By using ||, this method displays the item if any of its children are active OR if the item itself is active. The crucial point here is that the condition item.isActive is assessed AFTER considering its children recursively.

function displayItem(item: Item): boolean {
    const result: boolean = item.subItems.filter(subItem => displayItem(subItem)).length > 0 || item.isActive;
    // Perform logic to show the item based on the result
    return result;
}

Alternatively, you may find the following method clearer. The initial state of the result depends on the value of isActive, and subsequently, all children are checked recursively. If any child is found to be active, the result is set to true.

function displayItem(item: Item): boolean {
    let result: boolean = item.isActive;
    for (let subItem of item.subItems) {
        if (displayItem(subItem)) {
            result = true;
        }
    }
    // Perform logic to show the item based on the result
    return result;
}

Answer №2

After some thorough investigation, I developed a recursive approach that appears to be effective and efficient.

method.ts

  public hasActiveChildren(item: Item): boolean {
    // If the item has no sub items, always return false
    if (item.items == null || item.items.length < 0) {
      return false;
    }

    for (const i of item.items) {
      // If any sub item is active, always return true
      if (i.active === true) {
        return true;
      } else {
        // Otherwise, repeat the process
        return this.hasActiveChildren(i);
      }
    }
    
    // Default return value in case of compiler errors
    return false;
  }

Edit: The method performs well when an item only has one sub item at most. However, upon further testing, I discovered that it falls short in handling larger nested structures. Therefore, there is still room for improvement.

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

Triggering JSON schema validation event in React's Monaco Editor

I am interested in implementing custom JSON schema validation in my Monaco editor setup. Here is the current configuration: <MonacoEditor language="json" value={jsonValue} editorWillMount={(monaco) => { monaco.languages.json.jsonD ...

Creating a class and initializing it, then implementing it in other classes within an Angular application

Trying to grasp some angular fundamentals by creating a class structure. Unsure if this is the right approach. export class Cars{ Items:Car[]=[]; constructor() { this.Items = [ { id: "1", name: "Honda" ...

Storing the subscription value retrieved from an API in a global variable

I am trying to find a way to make the data retrieved from an API accessible as a global variable in Typescript. I know that using subscribe() prevents this, so I'm looking for a workaround. Here is the API code: getResultCount(category:any):Obs ...

Is there a way to trigger a custom event from a Web Component and then intercept it within a React Functional Component for further processing?

I'm facing an issue with dispatching a custom event called "select-date" from a custom web component date picker to a React functional component. Despite testing, the event doesn't seem to be reaching the intended component as expected. Below is ...

Typescript for managing the Shopify admin API

Is there anyone who can confirm whether Shopify offers typescript definitions for their admin API? I'm specifically interested in finding types for Orders, Products, and Variants. I initially assumed that this package would have them, but it seems l ...

unable to successfully complete parameter in angular 2

After receiving data from the API, I am using the subscribe method to execute lines of code. Below is the code snippet: this.attRecService.getAgendaData(moment(this.viewDate).format('YYYY-MM')).subscribe( resp => { this.ag ...

Struggling to track down the issue in my ts-node express project (Breakpoint being ignored due to generated code not being located)

For my current project, I decided to use the express-typescript-starter. However, when I attempted to debug using breakpoints in VS Code, I encountered an issue where it displayed a message saying "Breakpoint ignored because generated code not found (sourc ...

Guide on setting up global typing for AngularJS in your project

I have been working on a project that initially used the deprecated typings method for incorporating Typescript definitions. I now want to transition to using the @types method instead. Currently, we have a typings.json file located in the root of the pro ...

Version 5 of angularfie2 is encountering an issue where the type 'Observable<{}[]>' cannot be assigned to the type 'Observable<any[]>'

Encountering an error while using angularfire2 version 5: The error reads: "Type 'Observable<{}[]>' is not assignable to type Observable < any [] >." Code snippet: exercisesList$: Observable <any[]>; ionViewDidLoad() { ...

enhancing the types of parameters in a function declaration without relying on generics

My goal is to improve developer experience (DX) by expanding the types for parameters in a function signature. I want the tooltip when hovering over the following function to provide more detailed information: type Props = { a: number; }; const func = ( ...

An issue was encountered at node_modules/@fullcalendar/core/main.d.ts(1196,54), error TS1144: Expecting either '{' or ';'

When attempting to execute npm run build in my project, I encountered the following error: ERROR in node_modules/@fullcalendar/core/main.d.ts(1196,54): error TS1144: '{' or ';' expected. node_modules/@fullcalendar/core/main.d.ts(1197,34 ...

Passing parent form controls from an Angular 4 FormGroup to a child component

I have implemented Angular Reactive Forms FormGroup and FormArray in my project. The issue I am facing is related to splitting my form fields into child components and passing the parent form controls to them. I expected this to be a straightforward proces ...

Leverage glob patterns within TypeScript declaration files

Utilizing the file-loader webpack plugin allows for the conversion of media imports into their URLs. For example, in import src from './image.png', the variable src is treated as a string. To inform TypeScript about this behavior, one can create ...

The Server Components render encountered a glitch

Screenshot of the errorI am encountering a strange error only in the production environment. The lack of additional information leads me to believe it may be due to security measures put in place for production. Unfortunately, I have been unable to repli ...

Tips for creating a redirect to a specific page after clicking a link in an email using Angular

I've been working on implementing a feature in Angular where users can click on a link provided in an email and then get redirected to the respective page after authentication. I've tried a few different approaches, but none of them seem to be wo ...

Creating a dynamic path to an imported file in React: A step-by-step guide

Struggling with a dilemma regarding dynamically generated paths for importing files in React. I have utilized the map() function to generate a dynamic part of the code, consisting of a repetitive sequence of div elements, each housing an audio element. The ...

Is the autoIncrement property missing from the IDBObjectStore Interface in Typescript 1.8 lib.d.ts file?

Upon examining the specifications on various pages, it is evident that there is a specified read-only property named "autoIncrement" within the IDBObjectStore: https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore https://developer.mozilla.org/ ...

Even after making changes within my Angular and Firebase subscription, my variable remains unchanged

In an attempt to secure my Angular application's routes, I decided to create a canActivate method that would check the user's status. My backend is based on Firebase, and user authentication, login, and sign up functionalities are all handled thr ...

What is the significance of the exclamation mark in Vue Property Decorator?

As I continue to explore the integration of TypeScript with Vue, I have encountered a query about the declaration found in the Vue property decorator documentation. @Prop({ default: 'default value' }) readonly propB!: string ...

Tips on utilizing a pre-defined parametrized selector within the createSelector function

My goal is to create a selector based on a parametrized selector. I believe this approach will only emit when a specific item is updated, which aligns with my requirements. const getFeatureState = createFeatureSelector<FragmentsHierarchyState>(MY_FE ...