How display nested objects in Angular one per one

Viewed 1131

I trying to show nested object to select main or children object to add other inside

const categories = [
  {
    id: 1,
    title: 'Tecnology',
    subCategory: [
      {
        id: 3,
        title: 'JavaScript',
        subCategory: [
          {
            id: 4,
            title: 'Angular',
          },
        ],
      },
      {
        id: 5,
        title: 'C#',
      },
    ],
  },
  {
    id: 2,
    title: 'Health',
  },
];

my html

<div>
  <a
    class="dropdown-item"
    *ngFor="let category of categories"
  >

    {{ category.title }}
    <span
      *ngFor="let subCategory of category.subForumCategories"
    >
      > {{ subCategory.title }}
    </span>
  </a>
</div>

expected result

Tecnology
Tecnology > JavaScript
Tecnology > javaScript > Angualr
Tecnology > C#
Health

but i got the result

Tecnology > javaScript > C#
Health

in stackblitz: https://stackblitz.com/edit/angular-ivy-jfkszn?file=src/app/app.component.html

2 Answers

Probably better off working this out in typescript, and then iterating an array of strings instead of the objects. Angular templates are great for a lot of stuff, but this is probably starting to push it.

Here is an example of what you could have in ts

var categories = [{
    id: 1,
    title: "Technology",
    subCategory: [{
        id: 3,
        title: "JavaScript",
        subCategory: [{
          id: 4,
          title: "Angular"
        }]
      },
      {
        id: 4,
        title: "C#"
      }
    ]
  },
  {
    id: 2,
    title: "Health"
  }
];


getList();

function getList() {
  var list = extractSubCategories(categories);
  console.log(list);
}

function extractSubCategories(categories) {
  var list = [];
  for (var c of categories) {
    if (c.subCategory) {
      list.push(`> ${c.title}`);
      list.push(...extractSubCategories(c.subCategory).map(sc => `> ${c.title} ${sc}`));
    } else {
      list.push(`> ${c.title}`);
    }
  }
  return list;
}

template:

<div>
  <a class="dropdown-item" *ngFor="let category of getList()" > {{category}} </a>
</div>

You can create a recursive component. Then you can just pass in the object to display the way you want.

component.ts

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

@Component({
  selector: 'categories',
  template: `
     <div *ngFor="let category of categories">
        <div>
          {{titleHistory}} {{category.title}}
        </div>
        <categories[categories]="category.subCategory" 
                   [title]="titleHistory + category.title" 
                   [depth]="depth+1" 
                   *ngIf="category.subCategory"></categories>
    </div>`,
})
export class CommentComponent implements OnInit {
  @Input() categories: Categories;
  @Input() title: string = '';
  @Input() depth: number = 0;

  titleHistory = '';

  ngOnInit() {
    this.titleHistory = this.depth === 0 ? this.title : (this.title + ' > ');
  }
}

app.component.html

<categories [categories]="categoriesData"></categories>

stackblitz

Edit: updated stackblitz with more options

Related