问题描述
我正在做一些函数,使用PrimeNg库的组织结构图组件以树的形式显示获得的数据,从后端我得到一个对象数组,其中该数组的每个对象是树的一个节点,每个节点都有其 id 和 parent 属性,要验证它们是否是子节点,节点的 id 必须等于 parent 属性才能将其指定为子节点,我的问题在于组装树 如何制作递归算法 以便它遍历每个节点的所有子节点,而不管每个分支有多少子节点,从而能够在树中正确绘制它们,我附上了代码(与这段代码我已经可以带上单个节点的子节点了)。
您好。
//Formato de NgPrime para armar un nuevo nodo
nodo_nuevo = {
label:'',styleClass: 'department-cfo',expanded: true,data:{name:'',id_nodo:'',padre:''},children:[]
}
//Ejemplo de datos que llegan desde el backend
this.nodos = {
Estado: true,//Booleano
Respuesta: 'ok',//string
Dato: [
{
id_nodo: 1,//int
padre: undefined,//undefined o int
funcion: 'funcion 1',//String (nombre de la función)
menu: 'menu',//String (titulo de la funcion)
permitidos: { pasar_a_manual: true,cancelar: false,estado_servicio: true},id_funcion: 1,//int
orden: 1,//int
principal:true //booleano que identifica si el nodo es principal o no
},{
id_nodo: 2,//int
padre: 1,//undefined o int
funcion: 'funcion 2',//String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 2',estado_servicio: true },//array
id_funcion: 2,//int
orden: 2,//int
principal: false //booleano que identifica si el nodo es principal o no
},{
id_nodo: 3,//undefined o int
funcion: 'funcion 3',//String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 3',estado_servicio: true },//array
id_funcion: 3,//int
orden: 3,{
id_nodo: 4,//undefined o int
funcion: 'funcion 4',//String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 4',//array
id_funcion: 4,//int
orden: 4,{
id_nodo: 5,//int
padre: 4,//undefined o int
funcion: 'funcion 5',//String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 5',//array
id_funcion: 5,//int
orden: 5,]
}
//Funcion para convertir el json que me llega al json del arbol de NgPrime
armararbol(data){
this.data1 = [];
data.forEach((elemento,index) => {
this.nodo_nuevo.label = elemento.funcion
this.nodo_nuevo.data.name = elemento.funcion
this.nodo_nuevo.data.id_nodo = elemento.id_nodo
this.nodo_nuevo.data.padre = elemento.padre
//console.log(nodoprincipal)
this.data1.push(this.nodo_nuevo)
//Si el nodo principal tiene hijos
this.armarHijosArbol(data,this.nodo_nuevo)
});
}
//despues pasar aca la funcion para definir los hijos
armarHijosArbol(datos,dic){
datos.forEach((hijo,index) => {
if(dic.data.id_nodo === hijo.padre){
this.limpiarNodo()
this.nodo_nuevo.label = hijo.funcion
this.nodo_nuevo.data.name = hijo.funcion
this.nodo_nuevo.data.id_nodo = hijo.id_nodo
this.nodo_nuevo.data.padre = hijo.padre
this.data1[0].children.push(this.nodo_nuevo)
}
});
}
limpiarNodo(){
this.nodo_nuevo = {
label:'',children:[]
}
}
//Boton editar tag
.btn-editar{
background-color:#00786a;
}
//boton nuevo tag
.btn-nuevotag{
color: #00786a;
font: 120% Roboto;
font-weight: 500;
border: transparent;
background-color: transparent;
}
.titulo-tipo-tag{
font: 140% Roboto;
font-weight: 500;
}
.titulo-mensajes{
color: #414141;
font: 22px Roboto;
font-weight: 500;
width: 163px;
}
//item barra
/*.item-barra{
font: 120% Roboto;
}*/
//Estilos arbol
.company.ui-organizationchart .ui-organizationchart-node-content.ui-person {
padding: 0;
border: 0 none;
}
.node-header,.node-content {
padding: .5em .7em;
}
.node-header {
background-color: #495ebb;
color: #ffffff;
}
.node-content {
text-align: center;
border: 1px solid #404e91;
}
.node-content img {
border-radius: 50%;
}
.department-cfo {
background-color: #7247bc;
color: #ffffff;
border-radius: 20px;
text-transform: uppercase;
font-weight: bolder;
}
.department-coo {
background-color: #a534b6 !important;
color: #ffffff;
}
.department-cto {
background-color: #e9286f !important;
color: #ffffff;
}
.ui-person .ui-node-toggler {
color: #495ebb !important;
}
.department-cto .ui-node-toggler {
color: #8a0a39 !important;
}
.node-parent{
background-color: #e9286f !important;
color: #ffffff;
border: 1px solid #000;
}
.boton{
cursor: pointer;
}
<!-- Graficos de arbol dinamicos -->
<div class="col-md-8 mt-4">
<mat-tab-group>
<mat-tab label="Principal">
<p-organizationChart [value]="data1" selectionMode="single" [(selection)]="selectednode"
(onNodeselect)="onNodeselect($event)" (onNodeUnselect)="onNodeUnSelect($event)"
styleClass="company">
<ng-template let-node pTemplate="person">
<div class="node-header ui-corner-top">{{node.label}}</div>
<div class="node-content">
<div>{{ node.data.name }}</div>
</div>
</ng-template>
<ng-template let-node pTemplate="department">
{{ node.label }}
</ng-template>
</p-organizationChart>
</mat-tab>
</mat-tab-group>
</div>
解决方法
嗨,我已经使用了递归方法。请检查以下链接。
https://stackblitz.com/edit/angular-ivy-thnwdk?file=src%2Fapp%2Fapp.component.ts
以下两个函数是主要的
armarArbol(data) {
this.data1 = [];
// executes and set the root element where padre is undefined or null
const rootIndex = data.findIndex((item) => item.padre === undefined || item.padre === null );
this.nodo_nuevo.label = data[rootIndex].funcion;
this.nodo_nuevo.data.name = data[rootIndex].funcion;
this.nodo_nuevo.data.id_nodo = data[rootIndex].id_nodo;
this.nodo_nuevo.data.padre = data[rootIndex].padre;
this.data1.push(this.nodo_nuevo);
data.splice(rootIndex,1);
// this is the recurrsive method
this.setChild(+this.nodo_nuevo.data.id_nodo,data,this.data1[this.data1.length - 1 ].children);
}
// sets children in recurrsive way
private setChild(parentId: number,data: any,currentChild) {
if ( data.length > 0){
const filterArray = data.filter((item) => +item.padre === +parentId);
filterArray.forEach((item) => {
this.limpiarNodo();
this.nodo_nuevo.label = item.funcion;
this.nodo_nuevo.data.name = item.funcion;
this.nodo_nuevo.data.id_nodo = item.id_nodo;
this.nodo_nuevo.data.padre = item.padre;
currentChild.push(this.nodo_nuevo);
this.setChild(+this.nodo_nuevo.data.id_nodo,currentChild[currentChild.length -1].children);
});
}
}