javascript - function for delete nodes of tree
问题描述
good I am making a tree using primeng, I am doing the functions to be able to delete a node from the tree, I already have this function made that works well when I want to delete a node that has no children, and also when it only has a single child, but I giving problems when deleting a node that has more than one child. I think the problem is in the for of the function but I don't quite realize that it may be
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 de booleanos
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 de booleanos
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 de booleanos
id_funcion: 4, //int
orden: 4,//int
principal: false //booleano que identifica si el nodo es principal o no
},
{
id_nodo: 5, //int
padre: 3, //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 de booleanos
id_funcion: 5, //int
orden: 5,//int
principal: false //booleano que identifica si el nodo es principal o no
},
{
id_nodo: 6, //int
padre: 2, //undefined o int
funcion: 'funcion 6', //String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 6', //String (titulo de la funcion)
permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio: true }, //array de booleanos
id_funcion: 6, //int
orden: 6,//int
principal: false //booleano que identifica si el nodo es principal o no
},
{
id_nodo: 7, //int
padre: 3, //undefined o int
funcion: 'funcion 7', //String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 7', //String (titulo de la funcion)
permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio: true }, //array de booleanos
id_funcion: 7, //int
orden: 7,//int
principal: false //booleano que identifica si el nodo es principal o no
},
{
id_nodo: 8, //int
padre: undefined, //undefined o int
funcion: 'funcion 8', //String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 8', //String (titulo de la funcion)
permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio: true }, //array de booleanos
id_funcion: 8, //int
orden: 8,//int
principal: false //booleano que identifica si el nodo es principal o no
},
{
id_nodo: 9, //int
padre: 8, //undefined o int
funcion: 'funcion 9', //String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 9', //String (titulo de la funcion)
permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio: true }, //array de booleanos
id_funcion: 9, //int
orden: 9,//int
principal: false //booleano que identifica si el nodo es principal o no
},
{
id_nodo: 10, //int
padre: undefined, //undefined o int
funcion: 'funcion 10', //String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 10', //String (titulo de la funcion)
permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio: true }, //array de booleanos
id_funcion: 10, //int
orden: 10,//int
principal: false //booleano que identifica si el nodo es principal o no
},
{
id_nodo: 11, //int
padre: 10, //undefined o int
funcion: 'funcion 11', //String (nombre de la función) lo que hay que mostrar en los recuadros
menu: 'menu 11', //String (titulo de la funcion)
permitidos: { pasar_a_manual: true, cancelar: false, estado_servicio: true }, //array de booleanos
id_funcion: 11, //int
orden: 11,//int
principal: false //booleano que identifica si el nodo es principal o no
},
]
}
//Cartel Sweet Alert Error
mostrarCartelError(titulo, contenido) {
Swal({
title: '<b style="color:#000;">' + titulo + '</b>',
html: '<b style="color:#000;">' + contenido + '</b>',
type: 'error',
confirmButtonText: 'Aceptar',
background: 'rgb(0, 120, 106)',
confirmButtonColor: '#78cbf2',
timer: 10000
})
}
//Cartel Sweet Alert Correcto
mostrarCartelBien(titulo, contenido) {
Swal({
title: '<b style="color:#000;">' + titulo + '</b>',
html: '<b style="color:#000;">' + contenido + '</b>',
type: 'success',
confirmButtonText: 'Aceptar',
background: 'rgb(0, 120, 106)',
confirmButtonColor: '#78cbf2',
timer: 10000
})
}
//Variables para la funcion del nodo seleccionado
label: any
dataname: any;
padre: any
//Funcion si se selecciona un nodo
onNodeSelect(event) {
var label = event.node.data.id_nodo
var dataname = event.node.data.name
var padre = event.node.data.padre
//muestro los datos del arbol en la tabla
this.label = label
this.dataname = dataname
this.padre = padre
}
// funcion para borrar un nodo
borrarNodo(lista,idnodo) {
//this.mostrarCartelBien("Correcto", "nodo borrado con éxito")
//indice del nodo a borrar
let indice_nodo_borrar = lista.map((_, i) => i).filter(e => lista[e].id_nodo === idnodo);
//indices de los nodos hijos a borrar
let indice_nodo_borrar_hijos = lista.map((_, i) => i).filter(e => lista[e].padre === idnodo);
//indice parseado a int del indice del nodo a borrar
let indice_nodo_borrar_parseado = parseInt(indice_nodo_borrar)
//Si tiene hijos le aviso al usuario que se van a borrar los hijos del nodo seleccionado
if(indice_nodo_borrar_hijos.length > 0){
Swal({
title: '<b style="color:#000;">Atención</b>',
html: '<h5 style="color:#000;">Si borra este nodo también borrara su hijos ¿Desea Continuar?</h5>',
type: 'warning',
showCancelButton: true,
confirmButtonText: 'Si, borrar',
background: 'rgb(0, 120, 106)',
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
cancelButtonText: 'Cancelar',
}).then((result) => {
if(result.value){
for (let i = 0; i < indice_nodo_borrar_hijos.length; i++) {
//Borro el nodo
this.nodos.Dato.splice(indice_nodo_borrar_parseado,1)
//Borro los hijos del nodo
this.nodos.Dato.splice(indice_nodo_borrar_hijos[i],1)
//Actualizo el árbol
this.armarArbol(this.nodos.Dato)
}
}
})
//Si no tiene hijos solo borro el nodo seleccionado
}
else{
Swal({
title: '<b style="color:#000;">Atención</b>',
html: '<h5 style="color:#000;">¿Seguro que quiere borrar este nodo?</h5>',
type: 'warning',
showCancelButton: true,
confirmButtonText: 'Si, borrar',
background: 'rgb(0, 120, 106)',
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
cancelButtonText: 'Cancelar',
}).then((result) => {
if(result.value){
console.log("no tiene hijos")
this.nodos.Dato.splice(indice_nodo_borrar_parseado,1)
this.armarArbol(this.nodos.Dato)
}
})
}
}
//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: #00786a;
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;
}
<mat-tab label="Árbol">
<div class="col-md-12 d-flex">
<!-- Grafico de Arbol-->
<div class="col-md-8 mt-4">
<mat-tab-group >
<mat-tab *ngFor="let lista of lista_arboles; let indice = index" label="{{indice}}">
<div class="mt-3 pt-3">
<p-organizationChart [value]="lista" 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>
</div>
</mat-tab>
</mat-tab-group>
</div>
<!-- Fin Graficos de arbol dinamicos -->
<!-- Tabla dinamica de nodos -->
<div class="col-md-4 mt-4">
<table class="table table-striped">
<thead class="text-white" style="background-color: #00786a;">
<tr align="center">
<th class="font-weight-bolder" colspan="4">Nodo Seleccionado</th>
</tr>
</thead>
<thead>
<tr>
<th>Id Nodo</th>
<th>Funcion</th>
<th>Nodo Padre</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<tr>
<td ngDefaultControl name="label" [(ngModel)]="label" [innerHTML]="label"></td>
<td ngDefaultControl name="dataname" [(ngModel)]="dataname" [innerHTML]="dataname"></td>
<td ngDefaultControl name="padre" [(ngModel)]="padre" [innerHTML]="padre"></td>
<td>
<div class="row">
<button class="btn btn-sm" type="button" data-toggle="tooltip"
data-placement="top" title="Agregar Nodo"
(click)="!label ? abrirModalAgregarNodo(modal_nuevo_nodo) : abrirModalAgregarNodoHijo(modal_nuevo_nodo_hijo) ">
<img src="../assets/images/btn_nuevo_usuario.png" />
</button>
<button class="btn btn-sm" type="button" data-toggle="tooltip" data-placement="top" title="Editar nodo" [disabled]="!label" (click)="abrirModalEditarNodo(modal_editar_nodo)">
<img src="../assets/images/btn_editar.png" alt="Editar nodo" />
</button>
<button class="btn btn-sm" type="button" data-toggle="tooltip" data-placement="top"title="Borrar nodo" [disabled]="!label" (click)="borrarNodo(nodos.Dato,label)">
<img src="../assets/images/ic_trash.png" height="24px" alt="Borrar nodo" />
</button>
</div>
</td>
</tr>
</tbody>
</table>
<table style="margin-top: 50px;" class="table table-striped">
<thead class="text-white" style="background-color: #00786a;">
<tr style="font-weight: bolder;">
<th>Id Nodo</th>
<th>Funcion</th>
<th>Nodo Padre</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let tree of this.nodos.Dato; let index = index;">
<th title="Id nodo" scope="row">{{ tree.id_nodo }}</th>
<td title="Nombre la función del nodo">{{ tree.funcion }}</td>
<td title="Nodo padre">{{ tree.padre }}</td>
</tr>
</tbody>
</table>
</div>
<!-- Fin tabla dinamica de nodos -->
</div>
</mat-tab>
</mat-tab-group>
解决方案
I've provided a solution below. In this example, I've deleted id_nodo
1
. But this will work for any node id.
toDeleteList
will hold theid_nodo
s to delete- Push the base
id
onto the list - Filter the data for all direct children of the base
id
and return theirid
- Add those to the list
- For each direct child, call this function to repeat the process
- After the entire tree is scanned for children, filter the
data
array to remove any in thetoDeleteList
- return the filtered list, leaving the original array unaltered
const data=[{id_nodo:1,padre:null},{id_nodo:2,padre:1},{id_nodo:3,padre:1},{id_nodo:4,padre:1},{id_nodo:5,padre:3},{id_nodo:6,padre:2},{id_nodo:7,padre:3},{id_nodo:8,padre:null},{id_nodo:9,padre:8},{id_nodo:10,padre:null},{id_nodo:11,padre:10}];
let toDeleteList = [];
function deleteNode(id){
toDeleteList.push(id);
data.filter(d =>d.padre === id)
.forEach(child=>{
toDeleteList.push(child.id_nodo);
deleteNode(child.id_nodo);
});
return data.filter(d=>!toDeleteList.includes(d.id_nodo));
}
const result = deleteNode(1);
console.log(result);
推荐阅读
- java - 当布尔表达式为假时,for循环仍然有效
- java - 如何在 Java 中制作强化学习代理?
- mysql - 选择案例值 > 另一个案例值 + 2 的名称
- r - 消除每组内的 NA
- c# - 如何在 C# 中编写 LINQ 查询行号?
- c# - 对话总是在 Directline BOT 通道 websocket 中重新启动,如何保持流畅?
- php - 从对话中重定向
- node.js - 如何休息前缀:npm config set prefix /usr/local
- windows - 使用 Windows 身份验证的 Teradata 连接字符串
- java - Java Swing:实现信息窗口的好解决方案是什么?