Как удалить ветку вложенного дерева?

258
13 августа 2017, 06:50

Как удалить элемент из массива, чтобы удалялись вместе с ним и все остальные дочерние элементы? Что неправильно делаю? Логика такая: при нажатии на кнопку delete если в селект боксе ничего не выбрано, то ничего не происходит, а если выбрано, то мы удаляем из массива выбранный элемент, проверяем есть ли у остальных элементов parentId такой же как id у удаленного, если есть то удаляем их тоже, и снова проверяем есть ли у оставшихся parentId как id удаленных. Понимаю что надо использовать рекурсию, но все мои попытки приводят к зависанию браузера на несколько минут, а то и больше. Подскажите пожалуйста как правильно организовать удаление?

var twigs = { 
  "data": [{ 
      "id": 1, 
      "name": "Folder1", 
      "parentId": 0 
    }, 
    { 
      "id": 2, 
      "name": "Folder2", 
      "parentId": 1 
    }, 
    { 
      "id": 3, 
      "name": "Folder3", 
      "parentId": 1 
    }, 
    { 
      "id": 4, 
      "name": "Folder4", 
      "parentId": 3 
    }, 
    { 
      "id": 5, 
      "name": "Folder5", 
      "parentId": 3 
    }, 
    { 
      "id": 6, 
      "name": "Folder6", 
      "parentId": 2 
    }, 
    { 
      "id": 7, 
      "name": "Folder7", 
      "parentId": 4 
    }, 
    { 
      "id": 8, 
      "name": "Folder8", 
      "parentId": 7 
    }, 
    { 
      "id": 9, 
      "name": "Folder9", 
      "parentId": 6 
    }, 
    { 
      "id": 10, 
      "name": "Folder10", 
      "parentId": 0 
    }, 
    { 
      "id": 11, 
      "name": "Folder11", 
      "parentId": 8 
    }, 
    { 
      "id": 12, 
      "name": "Folder12", 
      "parentId": 6 
    }, 
    { 
      "id": 13, 
      "name": "Folder13", 
      "parentId": 4 
    } 
  ] 
}; 
 
jQuery(document).ready(function($) { 
 
  $("#add").on("click", function(event) { 
    event.preventDefault(); 
    var optionName = $("#title").val(); 
    var optionValue = twigs.data.length + 1; 
    $("<option/>").attr('value', optionValue).text(optionName).appendTo("#parent"); 
    if ($("#parent").val() == 0) { 
      twigs.data.push({ 
        id: twigs.data.length + 1, 
        name: optionName, 
        parentId: 0 
      }); 
    } else { 
      twigs.data.push({ 
        id: twigs.data.length + 1, 
        name: optionName, 
        parentId: parseInt($("#parent").val()) 
      }); 
    } 
 
    $("#tree").html(""); 
    var tree = createTree(twigs.data); 
    $('#tree').append(tree); 
    $("#parent").val(""); 
  }); 
 
 
 
 
 
function deleteTwig() { 
    var val = parseInt($("#parent").val()); 
    if (val !== 0) { 
            for (var i in twigs.data) { 
                deleted(i); 
                function deleted(i) { 
                    var id = parseInt(twigs.data[i]["id"]); 
                    var parentId = parseInt(twigs.data[i]["parentId"]); 
                    if (val === id) { 
                        twigs.data.splice(i, 1); 
                        if (id === parentId) { 
                            deleted(i); 
                        } 
                    } 
                } 
            } 
    } 
} 
 
 
$("#delete").on("click", function (event) { 
   event.preventDefault(); 
   deleteTwig(); 
 }); 
 
  function createTree(data, parentId) { 
 
    parentId = parentId || 0; 
    var items = data.filter(function(elem) { 
      return elem.parentId === parentId; 
    }); 
 
    if (items.length === 0) return null; 
 
    var tree = $('<ul>').addClass('tree'); 
    tree.append( 
      items.map( 
        function(elem) { 
          $("<option/>").attr('value', elem.id).text(new Array(parentId + 1).join("-") + elem.name).appendTo("#parent"); 
          var li = $('<li>').append( 
              $('<img src="images/folder.png">').addClass('state') 
            ).append( 
              $('<a>').html("<span>" + elem.name + "</span>").attr('id', elem.id).addClass('item') 
            ), 
            nestedTree = createTree(data, elem.id); 
 
          if (nestedTree !== null) { 
            li.append(nestedTree) 
              .addClass('collapse') 
          } 
          return li; 
        } 
      ) 
    ); 
    return tree; 
  } 
 
  var tree = createTree(twigs.data); 
 
  $('#tree').append(tree); 
 
  $('#tree') 
    .on('click', '.item', function() { 
      $('.active').not(this).removeClass('active'); 
      $(this).toggleClass('active'); 
    }) 
    .on('click', '.state', function() { 
      $(this).parent().toggleClass('collapse expand'); 
    }) 
 
});
img { 
  width: 20px; 
} 
 
select { 
  margin-top: 5px; 
  margin-bottom: 5px; 
  width: 173px; 
} 
 
button#add,#delete { 
  width: 173px; 
  height: 20px; 
} 
 
ul.tree { 
  list-style-type: none; 
  position: relative; 
} 
 
.active { 
  background-color: lightgrey; 
} 
 
.state { 
  position: absolute; 
  left: 1em; 
} 
 
.collapse>.state::after { 
  content: '+'; 
} 
 
.expand>.state::after { 
  content: '-'; 
} 
 
.collapse>ul { 
  display: none; 
} 
 
.expand>ul { 
  display: block; 
} 
 
.item { 
  cursor: pointer; 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<label for="title">Title:</label><br> 
<input type="text" id="title" name="title"><br> 
<select id="parent"> 
        <option value="0" selected="selected"></option> 
    </select><br> 
<button id="add">Add</button><br> 
<button id="delete">Delete</button><br> 
<div id="tree"></div>

Answer 1

Думаю что рекурсия должна выглядеть как-то так

var twigs = { 
  "data": [{ 
      "id": 1, 
      "name": "Folder1", 
      "parentId": 0 
    }, 
    { 
      "id": 2, 
      "name": "Folder2", 
      "parentId": 1 
    }, 
    { 
      "id": 3, 
      "name": "Folder3", 
      "parentId": 1 
    }, 
    { 
      "id": 4, 
      "name": "Folder4", 
      "parentId": 3 
    }, 
    { 
      "id": 5, 
      "name": "Folder5", 
      "parentId": 3 
    }, 
    { 
      "id": 6, 
      "name": "Folder6", 
      "parentId": 2 
    }, 
    { 
      "id": 7, 
      "name": "Folder7", 
      "parentId": 4 
    }, 
    { 
      "id": 8, 
      "name": "Folder8", 
      "parentId": 7 
    }, 
    { 
      "id": 9, 
      "name": "Folder9", 
      "parentId": 6 
    }, 
    { 
      "id": 10, 
      "name": "Folder10", 
      "parentId": 0 
    }, 
    { 
      "id": 11, 
      "name": "Folder11", 
      "parentId": 8 
    }, 
    { 
      "id": 12, 
      "name": "Folder12", 
      "parentId": 6 
    }, 
    { 
      "id": 13, 
      "name": "Folder13", 
      "parentId": 4 
    } 
  ] 
}; 
 
// Функция найдёт элементы с указанными атрибутом и его значением 
function findTwigs(attribute, value) { 
  var result = []; 
   
  for (var i = 0; i < twigs.data.length; i++) { 
    if (twigs.data[i][attribute] == value) { 
      result.push(twigs.data[i]); 
    } 
  } 
   
  return result; 
} 
 
// удалит текущий твиг и его потомков 
function deleteTwig(id) { 
  var twig = findTwigs('id', id)[0], // первый найденный элемент по "id" 
      children = findTwigs('parentId', id); // его дети 
 
  twigs.data.splice(twigs.data.indexOf(twig), 1); // удаляем найденный элемент 
   
  for (var i = 0; i < children.length; i++) { 
    deleteTwig(children[i].id); // повторяем алгоритм для всех потомков 
  } 
} 
 
deleteTwig(1); 
 
document.write(JSON.stringify(twigs.data));

Answer 2

Получилось что-то такое. При обходе, если находим искомую папку - удаляем ее, если дочернюю - добавляем ее id в очередь удаления и удаляем эту папку.

function deleteTwig() {
    var val = parseInt($("#parent").val());
    rmById(val);
}
function rmById(id) {
  var rmQueque = [id];
  for(var i = 0; i < rmQueque.length; i++) { // нельзя кэшировать rmQueque.length , т.к. добавляем элементы в очередь динамически
    for(var j in twigs.data) {
      if(twigs.data[j].id == rmQueque[i]) {
        // rm parent
        twigs.data.splice(j, 1);
      } else if(twigs.data[j].parentId == rmQueque[i]) {
        // rm child and add id to remove queque
        rmQueque.push(twigs.data[j].id);
        twigs.data.splice(j, 1);
      }
    }
  }
  console.log(twigs.data);
}
READ ALSO
CSS Hat горячие клавиши

CSS Hat горячие клавиши

Здравствуйте, есть ли возможность копировать сгенерированные стили css hut с помощью горячих клавиш? А то ведь не очень удобно, когда развернуто...

289
Wordpress не видит изображения в css файле

Wordpress не видит изображения в css файле

Все Привет, есть Wordpress и свой шаблон темы

334
&ldquo;Прыгают&rdquo; элементы на странице

“Прыгают” элементы на странице

Ребята бывает такая проблема - элементы (button, div) "прыгают" на странице (вернее они грузятся со стилем браузера, а потом подгружает css и плавно...

209
отфильтровать таблицу sqlite

отфильтровать таблицу sqlite

Добрый день Прошу помочь найти ошибкуЕсть следующая задача, дано три таблицы с однотипными данными: table1, table2, table3, у каждой из них есть всего...

307