Todo list

0

Witam ;)

Powoli wchodzę coraz głębiej w Js. Aktualnie próbuje stworzyć typową Todo listę z wyszukiwarką.

Przeczytałem wiele tutoriali i obejrzałem wiele video.
Wszędzie dodawanie polega na wystawieniu do głównego diva/listy elementu na końcu metodą appendChild() i podobnie z usuwaniem metodą remove().

Moja lista ma z założenia wrzucone trzy elementy początkowe, które pobrane są do nodeListy metodą queryselectorAll i zamienione na tablicę.

Problem pojawia się gdy zaczynam używać wyszukiwarki, tworzę nową tablicę filtrując po tablicy głównej i czyszcze kontener zadań, a nastepnie wyświetlam zawartość nowej tablicy.

Po skończeniu wyszukiwania (pusty input wyszukiwarki) wyświetlam znowu elementy podstawowej listy ale jak wiadomo nie zawierają one dodanych elementów metodą appendChild oraz zawierają usunięte elementy gdyż nie było żadnej ingerencji w pierwotną tablicę, tylko w DOM.

Jak rozwiązać ten problem? Spróbować dodawać elementy metodą push i w podobny sposób usuwać elementy, a dopiero potem zamiast dodawać tylko element do DOM, wyczyścić zawartość kontenera i ponownie wyświetlić całą tablicę elementów ? Jeżeli tak, to w jaki sposób uzyskać informacje i indeksie kliknietego elementu w celu usunięcia to z tablicy ?

1

Zrób wyszukiwarkę na zasadzie pokazywania i usuwania. Najłatwiej ;) Tutaj pokazuję jak https://4programmers.net/Foru[...]warka_z_filtrami_w_javascript

Jak chcesz po swojemu to wrzuć gdzieś kodzik, bo mi trudno sobie ułożyć w głowie jakie operacje i struktury danych tam trzymasz.

0

No to zacznijmy od tego, że pobieram na początek elementy

const taskList = [...document.querySelectorAll('.task')]; // lista tasków
const addForm = document.querySelector('.add-form');
const addTaskText = document.querySelector('.add-input');
const taskContainer = document.querySelector('.task-container'); // kontener na taski

Następnie w HTMLu mam mały formularz do dodawania tasków:

        <div class="add-container">
            <form action="" class="add-form"><input type="text" class="add-input"><button class="add-btn">Dodaj task!</button></form>

        </div>

a sposób dodawania i wyświetlania realizuje w JS w taki sposób:

const addTask = (e) => {
    e.preventDefault();
    const textContent = addTaskText.value;
    const newDiv = document.createElement('div');
    const newBtn = document.createElement('button');
    // newBtn.addEventListener('click', remove);
    newBtn.textContent = "USUŃ";
    newDiv.classList.add('task');
    newDiv.innerHTML = `<span class="task-text">${textContent}</span><input type="checkbox" name="" id="">`
    newDiv.appendChild(newBtn);
    taskList.push(newDiv);
    renderTask();
    addTaskText.value = '';
}

//Funkcja czyści cały DOM, który wyświetla taski i generuje ponownie z nowym, dodanym

function renderTask() {
    taskContainer.textContent = "";
    taskList.forEach((el)=>{
        taskContainer.appendChild(el);
    })
}

addForm.addEventListener('submit', addTask);

Rzeczą, która mnie zastanawia to, czy jest to logicznie i spójnie napisane? Wiadomo, że na początku mój kod nie będzie napisany idealnie, z zastosowaniem dobrych praktyk - dlatego pytam, czy proces logiczny jest w miarę okej ;)

0

Przeczytałem wiele tutoriali i obejrzałem wiele video.
Wszędzie dodawanie polega na wystawieniu do głównego diva/listy elementu na końcu metodą appendChild()
i podobnie z usuwaniem metodą remove().

Są dwa podejścia, chociaż ja zaraz napiszę o trzecim, które jest ich połączeniem.

Pierwsze - brzydkie, czyli to, co w tutorialach czytasz, że bezpośrednio zmieniasz strukturę DOM i potem masz p'ierdolnik, bo trzymasz dane w DOM

Drugie - ładne, czyli, że masz idealnie oddzieloną warstwę danych od interfejsu. Czyli eleganckie programowanie. Na tym bazują frameworki MVC albo biblioteki takie jak React. I ogólnie "ładne programowanie" nawet bez użycia frameworka. Że w zasadzie całą listę danych trzymasz sobie gdzieś osobno, a DOM tylko renderuje tę warstwę. Czyli coś takiego, że masz osobno listę zadań np.

const taskList = [
   {text: 'Odkurzyć'},
   {text: 'Zjeść'},
   {text: 'Pozmywać'},
];

i osobno szablon/widok (np. komponent React mógłby wyglądać tak:

const TaskList = ({ todos }) => {
    return <div>
    {
         todos.map(todo => <div>{todo.text}</div>);
    }
    </div>
}

Tylko, że DOM tak nie działa niestety. React robi dużo pod spodem*, żeby można było tak deklaratywnie programować, mimo, że DOM jest imperatywne. Ponieważ pewnie nie chcesz "robić swojego Reacta", to możesz trochę oszukać system. I trzymać dane zadań osobno, jednak każde zadanie miałoby przypisany do niego element DOM, który potem mógłbyś dodawać/zdejmować w razie potrzeby.

Czyli zadanie zamiast mieć postać:

{text: 'Posprzątać'}

Wyglądałoby tak:

{text: 'Posprzątać', el: TUTAJ_ELEMENT_DOM_KTORY_STWORZYLES}

Np. tak jak na tym jsfiddle:
https://jsfiddle.net/vw04juxh/2/

Tym sposobem DOM by reagował na twoje intencje, np. dodajesz taska - ląduje nowy element w DOM, filtrujesz, DOM się też filtruje.

tworzę nową tablicę filtrując po tablicy głównej

podejście, które zaproponowałem w ogóle nie trzyma tablicy filtrowanych elementów, ale po prostu przelatuje przez elementy i patrzy czy dany element powinien być usunięty czy dodany.

*np sprawdza z automatu, które dane się zmieniły, które elementy należy usunać, dodać, użyć ponownie itp. Z perspektywy użycia to tylko zrobienie szablonu, który wyświetla widok na podstawie danych, a z perspektywy Reacta kupę pracy.

0

Jak zwykle bardzo dużo informacji, trochę się rozjaśnia ale w takim przypadku pojawiają się kolejne pytania.

Ja w tablicy trzymam listę węzłów DOM z todo listy, aktualizuje to co dodanie elementu pushujac cały blok html do tej tablicy.

Z tego co piszesz zrozumiałem, że lepszym, a nawet bardziej spójnym sposobem byłoby w tablicy trzymanie tekstu, czyli textContentu, który otrzymuje podczas Tworzenia nowego taska, a zamykanie tego w blokach html powinno się odbywać dopiero podczas renderowania. Dla przykładu

Jeżeli mam zadanie: zrobić cos:
Do tablicy zadań push(input.value)

A dopiero podczas renderowania w metodzie forEach powinienem stworzyć znaczniki html które zostaną dodane metodą appendChild do drzewa dokumentu.

Mój task w html ma postać

<div> <span>$tekst</span><button>USUN</button></div>

Więc po kliknięciu na button powinienem pobierać textContent sąsiada, spana i usuwać taki element z tablicy, czy lepiej atrybut html data iterowac w pętli dla każdego buttona podczas renderowania np. Jako Index testu w tablicy i usuwać za pokmoca tego Indexu?

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0