I have angular application which contains Employ model class as follow:
export interface Employee {
name: string;
type: string;
subordinates: Employee[];
}
export declare class EmployeeEntity implements Employee {
name: string;
type: string;
subordinates: EmployeeEntity[];
supervisor?: EmployeeEntity;
constructor(orgStructure: string[], supervisor?: EmployeeEntity);
}
Employee cantains property "subordinates" as array of same datatype
In participant.component.ts file, it has given values as:
export class ParticipantComponent implements OnInit {
constructor() { }
empData: Employee= {
name: "Iron Man",
type: 'CEO',
subordinates: [
{
name: "Captain America",
type: 'VP',
subordinates: [
{
name: "Hawkeye",
type: 'manager',
subordinates: []
},
{
name: "Antman",
type: 'Manager',
subordinates: []
}
]
},
{
name: "Black Widow",
type: 'VP',
subordinates: [
{
name: "Hulk",
type: 'manager',
subordinates: [
{
name: "Spiderman",
type: 'Intern',
subordinates: []
}
]
},
{
name: "Thor",
type: 'Manager',
subordinates: [
{
name: "Loki",
type: 'Team Lead',
subordinates: []
}
]
}
]
}
]
};
ngOnInit(): void {
}
}
in participant.component.html file, Im intented to print the values from model class to organization chart.
<div class = "container">
<div class="tree" *ngIf="empData">
<ul>
<li>
<a href="#"> {{empData.name}} <br/>
{{empData.type}}
</a>
<ul>
<li *ngFor="let item of empData.subordinates">
<a href="#"> {{item.name}} <br/>
{{item.type}}
</a>
<ul>
<li *ngFor="let subitem of item.subordinates">
<a href="#"> {{subitem.name}} <br/>
{{subitem.type}}
</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
now the issue is, how long do i need to keep doing *ngFor to look for values. Is there anyway which looks for the array length or some other logic as there could be unlimited number of values? pls help me out
Here is the style file incase.
* {margin: 0; padding: 0;}
.tree ul {
padding-top: 20px; position: relative;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}
.tree li {
float: left; text-align: center;
list-style-type: none;
position: relative;
padding: 20px 5px 0 5px;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}
/*We will use ::before and ::after to draw the connectors*/
.tree li::before, .tree li::after{
content: '';
position: absolute; top: 0; right: 50%;
border-top: 1px solid #ccc;
width: 50%; height: 20px;
}
.tree li::after{
right: auto; left: 50%;
border-left: 1px solid #ccc;
}
/*We need to remove left-right connectors from elements without
any siblings*/
.tree li:only-child::after, .tree li:only-child::before {
display: none;
}
/*Remove space from the top of single children*/
.tree li:only-child{ padding-top: 0;}
/*Remove left connector from first child and
right connector from last child*/
.tree li:first-child::before, .tree li:last-child::after{
border: 0 none;
}
/*Adding back the vertical connector to the last nodes*/
.tree li:last-child::before{
border-right: 1px solid #ccc;
border-radius: 0 5px 0 0;
-webkit-border-radius: 0 5px 0 0;
-moz-border-radius: 0 5px 0 0;
}
.tree li:first-child::after{
border-radius: 5px 0 0 0;
-webkit-border-radius: 5px 0 0 0;
-moz-border-radius: 5px 0 0 0;
}
/*Time to add downward connectors from parents*/
.tree ul ul::before{
content: '';
position: absolute; top: 0; left: 50%;
border-left: 1px solid #ccc;
width: 0; height: 20px;
}
.tree li a{
border: 1px solid #ccc;
padding: 5px 10px;
text-decoration: none;
color: #666;
font-family: arial, verdana, tahoma;
font-size: 11px;
display: inline-block;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}
/*Time for some hover effects*/
/*We will apply the hover effect the the lineage of the element also*/
.tree li a:hover, .tree li a:hover+ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}
/*Connector styles on hover*/
.tree li a:hover+ul li::after,
.tree li a:hover+ul li::before,
.tree li a:hover+ul::before,
.tree li a:hover+ul ul::before{
border-color: #94a0b4;
}
What you want to achieve is recursion. You have a tree-like data structure that you want to traverse when rendering.
I would recommend creating a component that can call itself recursively to render any children (subordinates
).
employees.component.ts
@Component({
selector: 'employees',
templateUrl: './employees.component.html'
})
export class EmployeesComponent {
@Input() employees: Employee[];
}
<ul *ngIf="employees">
<li *ngFor="let employee of employees">
<div>{{employee.name}}</div>
<div>{{employee.type}}</div>
<div *ngIf="employee.subordinates?.length > 0">
<employees [employees]="employee.subordinates"></employees>
</div>
</li>
</ul>
The employees will render the array of Employee
provided in the @Input()
property. If any Employee
has any subordinates, the component will then call itself with those subordinates as the @Input()
property. And so on...
This will need to be kicked off from your initial data, which should also be an array.
app.component.ts
employees: Employee[] = [{
name: "Iron Man",
//... etc
}];
<employees [employees]="employees"></employees>