У меня есть список дел, и он работает просто отлично, но я пытаюсь отфильтровать его, но у меня возникают трудности. В принципе, каждая задача - это объект, у каждого объекта есть свойства text, id и checked. Я хочу, например, отображать только те задачи, которые не отмечены, когда я нажимаю кнопку Active.

Надеюсь, вы сможете помочь. Вот изображение для большей ясности:

Ui изображение


/*  Selectors  */
const switcher = document.querySelector(' input[Type="checkbox"]');
const body = document.body;
const formT = document.querySelector(`[data-new-todo-form]`)
const inputT = document.querySelector(`[data-new-todo-input]`)
const todoList = document.getElementById('todo-list');
const filterList = document.querySelector('.controls-list')

/* array that holds tasks */
let tasks = [];


/*  EVENT LISTENERS */
switcher.addEventListener('change', (e) => {
    if(e.target.checked) {
        body.classList.replace('light', 'dark')
    } else {
        body.classList.replace('dark', 'light')
    }

})


formT.addEventListener('submit', e => {
    e.preventDefault()
    
    let text = inputT.value.trim();
    if(text !== '') {
       addTask(text);
       inputT.value = '';
       inputT.focus();

    } 
 
})


todoList.addEventListener('click', e => {
    if (e.target.classList.contains('js-tick')) {
        const itemKey = e.target.parentElement.dataset.key;
        toggleDone(itemKey);
        
    }

    if (e.target.classList.contains('delete')) {
        const itemKey = e.target.parentElement.dataset.key;
        deleteTodo(itemKey);
        counter();
      }

      
    
});


document.addEventListener('DOMContentLoaded', () => {
    const ref = localStorage.getItem('tasksRef');
    if (ref) {
      tasks = JSON.parse(ref);
      tasks.forEach(task => {
        renderTodo(task);
        counter();
      });
    }
  });



  /* FUNCTIONS */

/* create a todo object */
const addTask = (text) => {
    const todoTask = {
        text,
        checked: false,
        id: Date.now(),
    }
    tasks.push(todoTask);
    renderTodo(todoTask);

};


const renderTodo = (todoTask)=> {

    localStorage.setItem('tasksRef', JSON.stringify(tasks));

    
    const item = document.querySelector(`[data-key='${todoTask.id}']`);

    if (todoTask.deleted) {
        // remove the item from the DOM
        item.remove();
        return
      }

    const isChecked = todoTask.checked ? 'done': '';

    const node = document.createElement('li')
    node.setAttribute('class', `todo-item ${isChecked}`);
    node.setAttribute('data-key', todoTask.id);
    node.innerHTML = `
    
    
    ${todoTask.text}
    cross`
    ;
    todoList.append(node);

    if (item) {
        node.replaceWith(item)
    } else {
        todoList.append(node)
    }
    counter();

}


const toggleDone = (key) => {
    
    const index = tasks.findIndex(task=> task.id === Number(key));

    tasks[index].checked = !tasks[index].checked;
    renderTodo(tasks[index]);
}

const deleteTodo = (key) => {
    const index = tasks.findIndex(item => item.id === Number(key));


    const todoTask = {
        deleted: true,
        ...tasks[index]
      };
      tasks = tasks.filter(item => item.id !== Number(key));
  renderTodo(todoTask);
}


const counter = () => {
    const itemsCounter =  tasks.filter(task=> !task.checked)
    const count = document.getElementById('todosLeft');

    const counterString = itemsCounter.length === 1 ? 'item' : 'items'

 count.innerText = `${itemsCounter.length} ${counterString} left`

}

Здесь HTML:


  

Todo

    <--! THE TASKS GOES HERE !-->

items left

  • All
  • Active
  • Completed
Clear Completed

Drag and drop to reorder list

Ответы (1)

Во-первых, список TodoList должен быть неизменяемым, потому что после нажатия на все TodoList должен показывать все Todos.

const renderActiveTodos = () => {
    const ref = localStorage.getItem('tasksRef');
    if (ref) {
      tasks = JSON.parse(ref);
      tasks.filter(item => !item.check).forEach(task => {
        renderTodo(task, true);
        counter();
      });
    }
}

const renderAllTodos = () => {
    const ref = localStorage.getItem('tasksRef');
    if (ref) {
      tasks = JSON.parse(ref);
      tasks.forEach(task => {
        renderTodo(task, true);
        counter();
      });
    }
}

const renderCompletedTodos = () => {
    const ref = localStorage.getItem('tasksRef');
    if (ref) {
      tasks = JSON.parse(ref);
      tasks.filter(item => item.check).forEach(task => {
        renderTodo(task, true);
        counter();
      });
    }
}

Но вы должны добавить preventMutableStorage в функцию renderTodo, чтобы предотвратить сохранение данных в локальном хранилище. Тогда вы сможете вернуть полный список todos, если вы нажмете кнопку all

const renderTodo = (todoTask, preventMutableStorage)=> {
    if(!preventMutableStorage){
        localStorage.setItem('tasksRef', JSON.stringify(tasks));
    }
    .....
}

Почему я изменяю renderTodo:

Сначала предположим, что у нас есть todoList = [{id:1, check:false}, {id:2, check:true}, {id:3, check:true}]

Когда я нажимаю кнопку active, вызывается renderActiveTodos:

It get data from localstorage
Filter data with check=false => [{id:1, check:false}]
Then we loop through it then call renderTodo
In renderTodo it first set the localstorage again then now the Todo in Localstorage is [{id:1, check:false}]

Тогда в следующий раз мы нажмем все:

It can't show [{id:2, check:true}, {id:3, check:true}] cause we already update the todoList in localstorage

По этой причине я добавил параметр preventMutableStorage, чтобы предотвратить обновление TodoList в локальном хранилище

.

Есть кое-что, что я только что понял в вашем коде. Но все будет исправлено, это рабочий код.

https://codepen.io/nguyennghi3489/pen/gOwvNga?editors=1111

2022 WebDevInsider