I'm trying to show a private group data from gitlab ( using a public one for testing ) and i'm using the Angular NestedTreeView to show each group with their subgroup, the parent nodes are showing normaly but i can't find a way to show their children, i have mapped the data to the way that the TreeView wants, the array with the data that i fetched from gitlab's api is showing fine with the parents and their children. Here's the code:
data.ts
export interface Data {
name: string;
id?: string;
children?: Data[]
}
data.service.ts
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(public http: HttpClient) { }
getEndpoint(id: string): string
{
return `https://gitlab.com/api/v4/groups/${id}/subgroups`
}
getRoot(): Observable<Data[]>{
return this.http.get<Data[]>(this.getEndpoint("9970")).pipe(
map((res: any) =>
res.map((data: Data) =>
{
return {
name: data.name,
id: data.id,
}
})
)
)
}
getNodes(subid: string): Observable<Data[]>
{
return this.http.get<Data[]>(this.getEndpoint(subid)).pipe(
map((res: any) =>
res.map((data: Data) =>
{
return {
name: data.name,
id: data.id,
}
})
)
)
}
}
sidebar.component.ts
@Injectable({
providedIn: 'root' })
@Component({
selector: 'app-sidebar',
templateUrl: './sidebar.component.html',
styleUrls: ['./sidebar.component.scss']
})
export class AppSidebarComponent implements OnDestroy,OnInit {
mobileQuery: MediaQueryList;
private _mobileQueryListener: () => void;
result: Data[] = [];
treeControl = new NestedTreeControl<Data>(node => node.children);
dataSource = new MatTreeNestedDataSource<Data>();
constructor(
changeDetectorRef: ChangeDetectorRef,
media: MediaMatcher,
public menuItems: MenuItems,
public http: HttpClient,
public dataService: DataService
) {
this.mobileQuery = media.matchMedia('(min-width: 768px)');
this._mobileQueryListener = () => changeDetectorRef.detectChanges();
this.mobileQuery.addListener(this._mobileQueryListener);
this.getRoots();
}
ngOnInit(): void {
}
getRoots()
{
this.dataService.getRoot().subscribe(response => {
this.result = response
this.result.forEach(directory => {
let nodeList: Data[]= []
this.dataService.getNodes(directory.id!).subscribe(response => {
nodeList = <Data[]> response
if(nodeList.length>0)
directory.children = nodeList;
nodeList = [];
})
});
console.log(this.result);
this.dataSource.data = this.result;
})
}
ngOnDestroy(): void {
this.mobileQuery.removeListener(this._mobileQueryListener);
}
hasChild = (_: number, node: Data) => !!node.children && node.children.length>0;
}
sidebar.component.html
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" >
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
{{node.name}}
</mat-tree-node>
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<div >
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'Toggle ' node.name">
<mat-icon >
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.name}}
</div>
<div [class.example-tree-invisible]="!treeControl.isExpanded(node)"
role="group">
<ng-container matTreeNodeOutlet></ng-container>
</div>
</mat-nested-tree-node>
</mat-tree>
CodePudding user response:
The main reason why they are not shown is that calling getNodes(..).subscribe
is not sync so u'll need a way to wait for them all. forkJoin
is possible solution
getRoots() {
this.dataService.getRoot().subscribe((response) => {
const result$ = forkJoin(
response.map((directory) => {
return this.dataService.getNodes(directory.id!).pipe(
map((children) => {
return {
...directory,
children,
};
})
);
})
);
result$.subscribe({
next: (result) => {
this.result = result as Data[];
this.dataSource.data = this.result;
},
});
})
}