首页 > 解决方案 > 递归算法以角度构建树

问题描述

我正在做一些函数,使用 PrimeNg 库的组织结构图组件以树的形式显示获得的数据,从后端我得到一个对象数组,其中该数组的每个对象都是一个节点树,每个节点都有它的 id 和 parent 属性,要验证它们是否是子节点,节点的 id 必须等于父属性才能将其指定为子节点,我的问题在于组装树的功能如何制作递归算法以便它遍历每个节点的所有子节点,而不管每个分支有多少子节点,从而能够在树中正确绘制它们,我附上了代码(我用这个代码已经可以带来单个节点的子节点)。

问候。

//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', //String (titulo de la funcion)
                    permitidos: { pasar_a_manual: true, cancelar: false, 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, //int
                    padre: 1, //undefined o int
                    funcion: 'funcion 3', //String (nombre de la función) lo que hay que       mostrar en los recuadros
                    menu: 'menu 3', //String (titulo de la funcion)
                    permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio:                       true }, //array
                    id_funcion: 3, //int
                    orden: 3,//int
                    principal: false //booleano que identifica si el nodo es principal o no
                },
                {
                    id_nodo: 4, //int
                    padre: 1, //undefined o int
                    funcion: 'funcion 4', //String (nombre de la función) lo que hay que                         mostrar en los recuadros
                    menu: 'menu 4', //String (titulo de la funcion)
                    permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio:                       true }, //array
                    id_funcion: 4, //int
                    orden: 4 ,//int
                    principal: false //booleano que identifica si el nodo es principal o no
                },
                {
                    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', //String (titulo de la funcion)
                    permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio:                       true }, //array
                    id_funcion: 5, //int
                    orden: 5 ,//int
                    principal: false //booleano que identifica si el nodo es principal o no
                },
            ]
        }
    

    //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:'',
            styleClass: 'department-cfo',
            expanded: true,
            data:{name:'',id_nodo:'',padre:''},
            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>

标签: javascriptangularprimeng

解决方案


嗨,我已经做了递归方法。请检查以下链接。

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, data, currentChild[currentChild.length -1].children);
        });
      }
  }

推荐阅读