@LoranDeMarcus

Не могу найти ошибку при удалении элементов, что делать?

Доброго времени суток, прошу помочь найти ошибку в коде. Уже весь день просидел, так и не понял как решить проблему.
Ошибка заключается в том, что после добавления элементов, неправильно удаляются элементы по клику. Удаляется не выбранный элемент. Почему то удаление начинается с 1 элемента. При удалении через кнопку "Clear Completed" при выборе выбранных, удаляются так же не выбранные элементы, а произвольные.

spoiler

<body>
<section id="todo_app">
  <header>
    <input id="new-todo" autofocus>
  </header>
  <section id="main" style="display: none;">
    <input id="toggle-all" type="checkbox"> <label for="toggle-all">Mark all as complete</label>
    <ul id="todo-list">
    </ul>
  </section>
  <footer id="footer" style="display: none;">
        <span class="todo-count">
          <strong class="count"> </strong> items left
        </span>
    <ul id="filters">
      <li>
        <a href="#" class="show-all-tasks">All</a>
      </li>
      <li>
        <a href="#" class="show-active-tasks">Active</a>
      </li>
      <li>
        <a href="#" class="show-completed-tasks">Completed</a>
      </li>
    </ul>
    <button id="clear-completed" style="display: none;">Clear completed</button>
  </footer>
</section>
<footer>
</footer>
</body>

var tasks = [];

function UpdateTasks () {
    $('#todo-list').find('li').remove();
    $(tasks).each(function (i, t) {
        $('#todo-list').append('<li class="' + t.status + '">\
            <div class="todo-task">\
            <input class="toggle" type="checkbox" data-id="' + t.id + '" ' + (t.status === 'completed' ? ' checked ' : '' ) + '><label class="text">' + t.title + '</label>\
            <button class="destroy"></button>\
            </div>\
            </li>');
        if ($('#todo-list li').hasClass('completed')) {
            $('#clear-completed').show();
        }
        if (!$('#todo-list li').hasClass('completed')) {
            $('#clear-completed').hide();
        }
    });
    ShowTasksCounter();
}

function ShowTasksCounter() {
    $('.count').text(tasks.length);
    if (tasks.length < 1) {
        $('#footer').hide();
    }
}

/* Добавление задач */

$('#new-todo').keyup(function (e) {
    const newId = GetNewUserId();
    if ((e.keyCode === 13)) {
        if ($(this).val() !== '') {
            $('#main').show();
            $('#footer').show();
            var $this = $(this);
            var newTask = $this.val();
            tasks.push({
                id: newId,
                title: newTask,
                status: 'active'});
            UpdateTasks();
            // Очистка Input
            $('#new-todo').val('');
        }
        else {
            return false;
        }
    }
});

/* Генерация id */

function GetNewUserId () {
    var maxId = tasks.reduce((max, item) => item.id > max ? item.id : max, 0);
    return maxId + 1;
}

/* Checkbox */

$('#todo-list').on('click', '.toggle', function (e) {
    var id = parseInt(e.target.dataset.id + 1);
    tasks[id].status = "completed";
    if (!$(this).prop("checked")) {
        tasks[id].status = "active";
    }
    UpdateTasks();
});

$('#toggle-all').on('click', function () {
    $(tasks).each(function (i) {
        if ($('#toggle-all').prop("checked")) {
            tasks[i].status = "completed";
        } else {
            tasks[i].status = "active";
        }
    });
    UpdateTasks();
});

/* Отображение выбранных задач */

$('.show-all-tasks').on('click', function() {
    $('li.active').show();
    $('li.completed').show();
    $(this).toggleClass('activated');
    $('.show-active-tasks').removeClass('activated');
    $('.show-completed-tasks').removeClass('activated');
});

$('.show-active-tasks').on('click', function() {
    $('li.active').show();
    $('li.completed').hide();
    $(this).toggleClass('activated');
    $('.show-all-tasks').removeClass('activated');
    $('.show-completed-tasks').removeClass('activated');
});

$('.show-completed-tasks').on('click', function() {
    $('li.active').hide();
    $('li.completed').show();
    $(this).toggleClass('activated');
    $('.show-all-tasks').removeClass('activated');
    $('.show-active-tasks').removeClass('activated');
});

/* Удаление */

$('#todo-list').on('click', 'button.destroy', function (e) {
    var id = parseInt(e.target.dataset.id);
    tasks.splice(id, 1);
    console.log(id);
    UpdateTasks();
});

function ShowTasks () {
    tasks.forEach(function (item, i, tasks) {
        console.log(tasks[i].id, tasks[i].title, tasks[i].status);
    });
}

/* События кнопки Clear Completed */

$('#clear-completed').on('click', function () {
    $('input:checked').parents('li').remove();
    $(tasks).each(function (i) {
        if (tasks[i].status === "completed") {
            tasks.splice(i, 1);
        }
    });
    UpdateTasks();
});


https://jsfiddle.net/0aw4dw37/3/
  • Вопрос задан
  • 155 просмотров
Решения вопроса 1
переписал код на чистый js
на кроссбраузрность не претендую, написан на ECMAScript 2015
в приложении этом есть недостатки, использовать его в реальной работе нельзя:
- постоянно обновляется весь DOM, этого делать нельзя, если удалили строку то обновить нужно только эту строку (и т. д.);
- обработчики навешиваются на DOM элементы, а работа по сути ведется с массивом данных, такой подход нужно реализовывать в совокупности с фреймворками (vue, riot, react и т.д.) изменил данные, рендер html отдать на откуп шаблонизатору фреймворка, он уже определит, что обновить;
- если уж использовать DOM, то от массива данных и вовсе можно отказаться, добавил строку, так и генерить новый элемент и добавлять его в DOM.

Ошибки по коду:
- использовать $(tasks).each для перебора массива это слишком, нужно использовать циклы, или методы работы с массивом;
- переменные объявлять вверху функции, например let i = 0, j = 1, k = 1; далее тело функции, так код проще читать;
- переменную стоит объявлять если она используется более одного раза;
- вместо $('#todo-list').find('li').remove(); $('#todo-list li').remove();
- вот так tasks[id] идет обращение к массиву данных по номеру элемента, но id не равен порядковому номеру элемента;
- tasks.splice(id, 1); аналогичная ошибка, по индексу удалиться случайный элемент а не по нужному id;
- $('#clear-completed').on('click', function () далее ерунда написана, удаляется DOM, потом удаляются данные, а потом заново все отрисовывается, в данном случае удаление DOM $('input:checked').parents('li').remove(); излишне;
- если уж использовать jQuery то dataset заменить на .data();

Как совет, прочитайте как работать с нативным js: переменные, массивы, объекты, функции, потом уже работа с DOM, а потом только посмотрите методы в jQuery, в голове сложится какая-то картина как устроен web frontend
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы