Exploring the Concept of Template Element Recursion in Angular JS 2

In my Angular 2 project, I encountered a situation where I needed to iterate through ngFor based on child elements. My component should be able to render a list based on the input provided. Here is an example of the data structure:

[
 {
   name: 'ABCD',
   child:[
     name: 'A1',
     child:[
      name: 'A1.1',
      child:[....]
     ]
   ] 
 }
]

I was able to render this structure inside my template by using component lifecycle ngOnInit and manipulating the DOM. Although it works, I am wondering if there is another way in Angular 2 to achieve this without directly manipulating the DOM. Perhaps using ngFor within the template or some other method. I have tried various approaches but have not had any success.

UPDATE: Attempted DOM manipulation

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'multiple-drop-down',
  template: `
  <div class="dropdown">
    <button id="dLabel" type="button" class="btn btn-primary"
    data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                 {{selected.size}} item selected<span class="caret"></span>
    </button>
    <ul class="dropdown-menu treeview" aria-labelledby="dropdownMenu">
        <li id="item-lists">
            <a href="javascript:void(0);" (click)="toggleItemSelect($event)">
                <input (change)="selectAll($event)" type="checkbox" id="checkbox-select-all">
                <label for="tall" class="custom-unchecked">Select All</label>
            </a>
        </li>
    </ul>
  </div>
   `,
 })
 export class MultipleDropDownComponent implements OnInit {
 menuItemList: Array<MenuObject>;
 selected: Set<string>;

 constructor() {
   this.selected = new Set<string>();
   this.menuItemList = [
     { name: 'item 1', id: 'A', child: [
       { name: 'item 1.1', id: 'A1', child: [
           { name: 'item 1.11', id: 'Aa1', child: []},
           { name: 'item 1.12', id: 'Aa2', child: []},
           { name: 'item 1.13', id: 'Aa3', child: []}
       ]},
       { name: 'item 1.2', id: 'A2', child: []}]},
    { name: 'item 2', id: 'B', child: []},
    { name: 'item 3', id: 'C', child: []},
    { name: 'item 4', id: 'D', child: []}];
  }

  ngOnInit() {

    // calling render method to populate dropdown values
    this.renderChildElements('item-lists', this.menuItemList , 'first');
  }

  renderChildElements(id: string, items: MenuObject[], key: string): void {
    let parent = this.createULElement(id, key);
    items.forEach((element: MenuObject) => {
        let Li = document.createElement('li');
        Li.setAttribute('id', element.id);
        Li.innerHTML = `<a href="javscript:void(0);"
                        (click)="toggleItemSelect($event)">
                        <input type="checkbox" name="` + element.name + `"
                        id="` + element.id + `" (click)="toggleMultiSelect($event, ` + element + `)">
                        <label for="tall-1" class="custom-unchecked">` + element.name + `</label>
                        </a>`;
        document.querySelector('#' + parent).appendChild(Li);

        // this condition is responsible for recurrsion process
        if ( element.child.length > 0 ) {
            this.renderChildElements(element.id, element.child, element.id);
        }
    });
  }
  createULElement(parentId: string, childId: string): string {
    let ulId = childId + 'ul';
    let newUl = document.createElement('ul');
    newUl.setAttribute('id', ulId);
    document.querySelector('#' + parentId).appendChild(newUl);
    return ulId;
  }
}
export interface MenuObject {
   id: string;
   name: string;
   child?: MenuObject[];
}

Answer №1

Here is the solution you are looking for:

@Component({
  selector: 'child',
  template: `
<div>{{data?.name}}</div>
<child [data]="data?.child]></child>`
})
class ChildComponent {
  @Input() data;
}
@Component({
  selector: 'my-app',
  template: `
<child [data]="data?.child]></child>`
})
class ChildComponent {
data = [
 {
   name: 'ABCD',
   child:[{
     name: 'A1',
     child:[{
      name: 'A1.1',
      child:[....]
     }]
   }] 
 }
];
}

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

What could be the reason for the malfunction of my checkbox styling?

I have designed custom checkboxes and radio buttons with CSS styling as shown below: input[type="checkbox"]:checked + label:after, input[type="checkbox"][checked="checked"] + label:after, input[type="radio"][checked="checked"] + label:after, input[type="r ...

Utilize promise-style for Sequelize associations instead, please

I am in the process of merging information from 3 tables - Products, Suppliers, and Categories. My goal is to retrieve the row with SupplierID = 13. I recently came across a helpful explanation on How to implement many to many association in sequelize, whi ...

Having trouble with ng-click not correctly updating values within ng-repeat

Here is the code snippet: <div ng-repeat="data in products"> <div class=edit ng-click="dataUI.showEdit = true; content = data;"> </div> <div ng-repeat="renew in data.renewed"> <div class=edit ng-click="dataUI ...

Creating a nested list of objects in JavaScript can be achieved by using arrays within objects

I'm currently in the process of creating a new Product instance in Javascript, with the intention of sending it to the server using [webmethod]. [WebMethod] public static void SetProduct(Product product) { // I need the Product instance ...

Edge browser experiencing delays with dynamic select options in Angular 2

I am currently utilizing an *ngFor loop in Angular 2 Version: 4.0.1 to populate 5 select lists on a webpage with the given code: select [(ngModel)]="_materialInput.code" (change)="onChange()" formControlName="code" class="form-control" id="code"> & ...

What is the best way to trigger a controller action using jQuery in your application.js file?

Currently, I am incorporating the jQuery autocomplete plugin into my project and looking to personalize a specific event: select: function(event, ui) { $('.topic_field').val(ui.item.topic.name); return false; This event es ...

Switching between pages and updating the URL without needing to refresh the page, while still maintaining the content even after a refresh

After experimenting with jQuery's load() method to dynamically change content without refreshing the page, I encountered a recurring issue: the URL remains unchanged. Even when attempting to use history.pushState() to modify the URL, the problem pers ...

Troubleshooting the Nextjs-blog tutorial loading issue on localhost:3000

Looking to delve into Nextjs, I decided to start by following a tutorial. However, every time I attempt to run 'npm run dev', the local host just keeps loading endlessly. Upon inspecting and checking the console, there is no feedback whatsoever. ...

What is the best way to utilize the same module across multiple files within a single project?

After learning that modules are cached when required, as explained in this post, I am wondering what the most efficient way is to write clean and readable code out of the various approaches available. Situation: I have three files named A, B, and C. All ...

What's the deal with dynamic prop values in React?

In my React application, I am trying to set a dynamic prop value. My goal is to use the first item in an array called Fruits and concatenate it with 'prop' to create the prop value. For example: ApplesProp index.js const ApplesProp = { Name: "G ...

[Vue alert]: Component mounting failed due to usage of mixin with a parameter

For the past day, I've been facing difficulties creating a Vue mixin with a parameter. When attempting to do so, I encounter a [Vue warn]: Failed to mount component: template or render function not defined error. Below is my JS file which includes the ...

React infinite scroller - component fails to work when initial items are insufficiently loaded

In my Next.js app, I am dealing with a large firestore database containing many book objects. To filter these books based on keywords in their title, category, author, etc., I have implemented a searchbar. Due to the sheer volume of books, I am utilizing l ...

Setting a default value for Autocomplete in MaterialUI and React.js

Is there a way to set a default value for an Autocomplete TextField component from Material UI in React.js? I want to load a pre-populated value from the user's profile that can then be changed by selecting another option from a list. Check out my co ...

Slider Jquery - Displaying Half-Step Visual Bar Lengths

JSFIDDLE $(function() { $( "#slider-range-min" ).slider({ range: "min", value: 5, min: 0, step: .5, max: 10, slide: function( event, ui ) { $( "#amount" ).val(ui.value); ...

Trouble locating DOM element in Angular's ngAfterViewInit()

Currently, I am attempting to target a specific menu item element within my navigation that has an active class applied to it. This is in order to implement some customized animations. export class NavComponent implements AfterViewInit { @ViewChild(&a ...

What purpose does @ViewChild serve if we are unable to modify or interact with its properties from the Parent Component?

I have two main components - home and about. Within both of these, I am including a third component called hearts. Currently, I am manipulating the value of the 'age' property in the hearts component (initially set to '23') using @ViewC ...

Exploring AngularJS: A closer look at ngOptions expressions

I have been struggling to populate a Select element with a list of objects for ngOptions. Despite confirming that the data structure is correct and accessible, I cannot get the Select to show the options. Even when rendering the options expression on the p ...

Access the elements within arrays without using the square brackets

I am trying to access data from a list, but I am having trouble using square brackets []. The getTalonPaie function calls the get method from the HttpClient service and returns an observable with multiple values. However, when I try to store these values i ...

Ways to remove specific characters from the escape() function in express-validators

When using the check method from express-validator to validate user input, I'm curious if there's a way to exclude certain characters from the test. For example, currently I have: check("profile.about").trim().escape() This code snippet convert ...

The express-unless plugin in Node.js allows you to exclude specific paths from the middleware.auth

I need help implementing express-unless to exclude a /health path from using middleware.auth. Unfortunately, I am facing syntax issues and unable to test this locally. Using localSite == true is not compatible with my environment. The error logs are shown ...