Jacopo Sciampi
Jacopo Sciampi

Reputation: 3433

Multidimensional array iteration with ngFor

I have a dataset like that:

   [
        {
            prop1: "",
            prop2: "",
            child: [
                prop1: "",
                prop2: "",
                    child: [
                    ...
                    ]
            ]
        },
        {
            prop1: "",
            prop2: "",
            child: [
                prop1: "",
                prop2: "",
                    child: [
                    ...
                    ]
            ]
        }
    ],
[
        {
            prop1: "",
            prop2: "",
            child: [
                prop1: "",
                prop2: "",
                    child: [
                    ...
                    ]
            ]
        },
        {
            prop1: "",
            prop2: "",
            child: [
                prop1: "",
                prop2: "",
                    child: [
                    ...
                    ]
            ]
        }
    ],

This can go deeper forever, it is not a two or three-dimensional array. It is an N-dimensional array. I was thinking of how to properly iterate it in the HTML, but using nested ngFor would be a suicide and kinda impossible since, as I said, I don't know how many nested children I will have.

What I want is a tree view of that dataSet.

What could be a good solution to this?

Upvotes: 0

Views: 610

Answers (2)

Ostn
Ostn

Reputation: 813

You can use a recursive component, let call it displayobject. For each level, the displayobject component list the properties, if the property is a string then it displays it, otherwise it loads a new displayobject component that do the same thing with the given object.

Template :

<div *ngFor="let property of propertyList">

    <span *ngIf="isString(myObject[property])"> 
        {{ property }} 
    </span>

    <displayobject *ngIf="isObject(myObject[property])" [myObject]="myObject[property]">
    </displayobject>

</div>

Component :

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

@Component({
    selector: 'displayobject',
    ...
})
export class DisplayObject {

    @Input() myObject;
    public propertyList = [];

    ngOnChanges() {
        this.propertyList = Object.keys(this.myObject);
    }
}

And you call it :

 <displayobject [myObject]="yourObject"></displayobject>

Upvotes: 2

VRoxa
VRoxa

Reputation: 1051

Following @Noelmout solution but getting in a simpler way.

The idea is the set a recursive component.
Since the data set you just shown satisfies a pattern like {prop1: "", prop2: "", child: [...]} and so on. Consider a component to render recursively and typed.

*.ts

type Item = {
  prop1: string,
  prop2: string,
  child: Item[];
}

@Component({
  selector: 'item-display',
  templateUrl: './item-display.html',
  styleUrls: ['./item-display.component.scss']
})
export class ItemDisplayComponent {
  @Input() item: Item;
}

*.html

<div class="content">

    <div class="prop1">{{ item.prop1 }}</div>
    <div class="prop2">{{ item.prop2 }}</div>

    <div class="child" *ngFor="let c of item.child">
        <item-display [item]="c"></item-display>
    </div>

</div>

Now, you can modify anything on the component that will be applied to all the nested components.
Even more, add a depth attribute, if needed

...
@Input() depth: number = 0; // or 1, up to you
<item-display [item]="c" [depth]="depth + 1"></item-display>

And finally, since you have a collection of that items, from you root component

<div class="item-display" *ngFor="let item of rootItems">
    <item-display [item]="item"></item-display>
</div>

No need to set the depth property because has a default value (and better off not to expose that property, it is like a internal field just know by ItemDisplayComponent).

Upvotes: 2

Related Questions