Check Liste JavaScript

Cark

Cadet 4th Year
Registriert
Mai 2022
Beiträge
86
---------------------------------------------------------------VORSTELLUNG----------------------------------------------------------------
Einen schönen guten Tag an das CB Forum! Ich habe hier keinen Vorstellungsthread gefunden, deshalb stelle ich mich hier mal kurz vor bevor ich mit der Frage beginne. Ich bin der Marc 27 Jahre alt und komme aus der Region um Hannover rum. Hobbymäßig lerne ich zurzeit JavaScript und lese hier gerne in den Hardware Bereichen mit um bisschen was an Wissen mitzunehmen.
Auf ein gutes miteinander
---------------------------------------------------------------VORSTELLUNG ENDE---------------------------------------------------------

Ich habe 3 folgende Problem was mich ziemlich dumm fühlen lässt und langsam schon herunterzieht.

1. Das eingeben und das erzeugen der Listeneinträge to Do's klappt. Sobald ich die Seite aber neu lade verschwindet der "check" Status und bei neuer Eingabe verschwinden die vorherigen Einträge unter CheckList und es steht nur noch der aktuell eingegebene Punkt da, der die vorherigen 2 verschwinden lassen hat.

Nach meinen Gedanken ist das Problem, dass sich "i" nach jedem neu Laden auf 0 bzw. nicht deklariert zurücksetzt und ich per if Abfrage sobald userInputStorage "true bzw. nicht mehr null" ist dann für i den Wert von closeBtn.length nehme, da diese ja immer die aktuelle Länge der Liste hat und sich nach dem neu Laden nicht zurücksetzt. Nur funktioniert leider nicht.
Ist meine Annahme aber richtig das ich eine zweite Option per if nach dem neu Laden einbringen muss die dann die aktuelle Länge der Liste berücksichtigt? Wie schaffe ich es nach dem neu Laden die Liste fließend weiter fortzuführen?

2. Wenn ich einen Listeneintrag "removen" möchte werden geich alle Einträge "removed" + dem "ul bzw. #toDoList" Tag aus der HTML Datei.

Ich vermute daran das meine <li> tag nicht an die "ul bzw #toDoList" angehängt ist doch wenn ich das mit #toDoList.append(li); versuche funktioniert es nicht.
Ist diese Annahme auch richtig und nur mein Horizont zu begrenzt um es richtig umzusetzen?

3. Ist das Problem das sich der "checked" Status eines Listeneintrags nach jedem neu Laden zurücksetzt. Muss ich diesen auch im localStorage speichern und falls ja wie?

Ich habe schon sovieles mit verschiedensten Annahmen probiert aber bin jedes mal gescheitert außerdem ist mein Gehirn so oft geplatzt und mittlerweile ein labriger Haufen.

Ich wäre euch super super dankbar wenn ihr mir helfen könnt!

Gruß Marc

HTML:
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Creative Checklist</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>

    <div id="pageContent">

    <div id="inputContainer">
        <input type="text" id="inputField">
        <span class="placeholder">To do einfügen</span>
        <button id="saveInputBtn">SPEICHERN</button>
    </div>


    <div id="checkListContainer">
        <h1>Check List</h1>

        <ul id="toDoList">
        </ul>
    </div>

</div>

    <script src="app.js"></script>
    
</body>
</html>
Javascript:
let inputField = document.querySelector('#inputField');
let toDoList = document.querySelector('#toDoList');
let saveInputBtn = document.querySelector('#saveInputBtn');
let userInput = [];
let userInputStorage = JSON.parse(localStorage.getItem('userInput'));
let closeBtn = document.getElementsByClassName ("closeBtn");
let li = document.getElementsByTagName('li');


saveInputBtn.addEventListener('click', () => {

   userInput.push(`<li><input class="check1" type="checkbox"> <span class="toDoText"> ${inputField.value} </span> <i class="closeBtn">\u00D7</i></li>`);
   inputField.value = "";
   localStorage.setItem('userInput', JSON.stringify(userInput));
   listitem = [];

  // if(userInputStorage == null) {
   for(i = 0; i < userInput.length; i++){
   listitem +=  userInput[i] ;
   }
   toDoList.innerHTML = listitem;
//   }

/*
else {
   for(i = closeBtn.length; i < closeBtn.length; i++){
      listitem += userInput[i];
   }
   toDoList.innerHTML = listitem;
}
*/
  
   for (j = 0; j < closeBtn.length; j++) {
      closeBtn[j].onclick = function () {
         var div = this.parentElement;
         div.parentElement.remove();
      }
    }
});

if (userInputStorage) {
   listitem = userInputStorage.join(' '); // remove comma
   toDoList.innerHTML = listitem;
};

for (j = 0; j < closeBtn.length; j++) {
   closeBtn[j].onclick = function () {
      var div = this.parentElement;
      div.parentElement.remove();
   }
 };
 

Anhänge

  • Screenshot (4).png
    Screenshot (4).png
    97,2 KB · Aufrufe: 193
  • Screenshot (5).png
    Screenshot (5).png
    122,7 KB · Aufrufe: 190
  • Screenshot (6).png
    Screenshot (6).png
    119,8 KB · Aufrufe: 191
  • Gefällt mir
Reaktionen: BAGZZlash
In deinem Coding sind diverse Fehler und auch wirklich viel schlechter Stil. Das ist aber am Anfang auch absolut legitim :)

  • Warum geht nur Klick und kein Enter beim Aufgabe anlegen?
  • Wo sind die Funktionen zum Speichern des Status (Erledigt/Gelöscht)?
  • Warum speicherst du den kompletten HTML-Code einer Aufgabe im LocalStorage?
  • ...

Es gibt für dein Projekt ein gutes und ausführliches Tutorial. Daher lies dir das mal durch: https://www.tutorialstonight.com/to-do-list-javascript.php
 
  • Gefällt mir
Reaktionen: Cark
Cark schrieb:
Sobald ich die Seite aber neu lade verschwindet der "check" Status und bei neuer Eingabe verschwinden die vorherigen Einträge unter CheckList und es steht nur noch der aktuell eingegebene Punkt da, der die vorherigen 2 verschwinden lassen hat.
Du speicherst im Storage ja auch nicht den Status der Listeneinträge sondern du schreibst da nur rein, wenn du den Eintrag gerade jungfräulich erzeugt hast. Generell würde ich nicht das ganze HTML speichern sondern nur was dich interessiert und das am besten als JSON (im Ansatz machst du das ja auch). Die Struktur sollte etwa wie folgt aussehen:
JSON:
[
    {
        "task": "Wäsche waschen",
        "checked": true
    },
    {
        "task": "CB um Hilfe bitten",
        "checked": false
    },
    ...
]
Daraus kannst du dir dann dein HTML dann wieder zusammenbauen. Den checked Status musst du entsprechend immer aktualisieren, wenn er geändert wird.

Das Überschreiben kommt daher, dass du ja den Userinput nimmst und anschließend alles überschreibst (innerHTML = ...) anstatt nur hinzuzufügen. Besser als das HTML selbst zu erzeugen ist es die Elemente per document.createElement zu erzeugen und per appendChild zusammenzufügen.

Für mehr reicht meine Zeit leider gerade nicht.
 
  • Gefällt mir
Reaktionen: Cark
Danke blablub1212 und Freezedevil für die Tipps :)

blablub1212

was meinst du denn mit schlechten Stil? Ich lese und schaue Videos über JavaScript dazu versuche ich noch einige Projekte nebenbei selbstständig zu "coden". Die Gelegenheit das sich jemand meinen Code anguckt und verbessert habe ich sonst nicht. Wie muss ein guter Stil denn aussehen. Der Link ist echt gut! Alles verstehe ich noch nicht werde mir das aber heute/morgen genauer angucken und mit Hilfe von Google hoffentlich auch die Dinge verstehen die ich noch nicht verstehe :D
 
Alleine den Codeblock für den Eventhandler für die "closeBtn" (die außerdem nicht closen sondern deleten, Stichwort transparente Nomenklatur) doppelt im Main und im Callback fürs Speichern zu haben ist pretty ugly. Dann unstrukturierte Datenablage wie @Freezedevil geschrieben hat und die Variablen i und j die mangels expliziter Deklaration das Window Object zumüllen.
Alles nicht super tragisch, da kommst du schon dahinter. Aber manchmal lernt man solche Sachen erst wenns weh tut :D (insb. scoping)
 
  • Gefällt mir
Reaktionen: Cark
blablub1212 schrieb:
  • Warum geht nur Klick und kein Enter beim Aufgabe anlegen?
  • Wo sind die Funktionen zum Speichern des Status (Erledigt/Gelöscht)?
  • Warum speicherst du den kompletten HTML-Code einer Aufgabe im LocalStorage?
  • ...
Hab das heute Mittag überlesen, tut mir leid mein Fehler.

1. Das habe ich mich tatsächlich auch gefragt :D glaube mit einem <input type="button oder mit submit" geht es.
2. Jetzt fange ich schon an zu schwitzen...
3. Error Gehirn wird automatisch heruntergefahren

Mit localStorage bin ich erstmal komplett überfordert. Gerade mit den umwandeln (JSONparse/stringify), wobei es jetzt geht ich glaube bei localStorage.setItem immer nur stringify, falls nötig und beim getItem immer mit Parse umwandeln (wäre jedenfalls einfach zu merken :D). Morgen befasse ich mich richtig damit. Dann kann ich dir hoffentlich Antworten liefern!
Ergänzung ()

floq0r schrieb:
Alleine den Codeblock für den Eventhandler für die "closeBtn" (die außerdem nicht closen sondern deleten, Stichwort transparente Nomenklatur) doppelt im Main und im Callback fürs Speichern zu haben ist pretty ugly. Dann unstrukturierte Datenablage wie @Freezedevil geschrieben hat und die Variablen i und j die mangels expliziter Deklaration das Window Object zumüllen.
Alles nicht super tragisch, da kommst du schon dahinter. Aber manchmal lernt man solche Sachen erst wenns weh tut :D (insb. scoping)
ok Danke dir! :) Das versuche ich zu berücksichtigen das mit den doppelten Codeblock beim closeBtn habe ich nur gemacht, weil ich damit auch nach dem neu laden der Seite die gespeicherten Listeneinträge schließen konnte, was ohne den zweiten codeBtn Block nicht ging. Da konnte ich das x zum schließen nur anklicken wenn ich die Seite noch nicht neu geladen hatte. Das war mein bescheidener Lösungsansatz :D Habe mich schon wie ein König gefreut, als ich selbstständig ein Snake Game gemacht habe. Das zeige ich aber besser nicht :O hehe.
Wie noch mehr schmerzen? Es tut doch schon genug weh :/. Bewundere euch schon ein wenig dafür das ihr euch nur einen Code angucken müsst und dann "zack" das ist der Fehler und das die Lösung. Hoffe da komme ich auch noch hin aber je mehr ich lerne desto unwissender komme ich mir vor :p
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: floq0r
Hello again. Ich habe mir jetzt den Link genauer angeguckt und alles Schritt für Schritt durchgenommen. Leider verstehe ich noch nicht alles und wollte euch fragen, ob ich die Code Zeilen so richtig interpretiere.

Javascript:
 let tasks = Array.from(JSON.parse(localStorage.getItem("tasks")));

  tasks.forEach(task => {
    const list = document.querySelector("ul");
    const li = document.createElement("li");
    li.innerHTML = `<input type="checkbox" onclick="taskComplete(this)" class="check" ${task.completed ? 'checked' : ''}>
          <input type="text" value="${task.task}" class="task ${task.completed ? 'completed' : ''}" onfocus="getCurrentTask(this)" onblur="editTask(this)">
          <i class="fa fa-trash" onclick="removeTask(this)"></i>`;
    list.insertBefore(li, list.children[0]);
  });

1. Hier geht es mir um den Code "${task.task}". Also das man speziell bestimmte Wert eines Elements mit der stelle nach den Punkt ansprechen kann kenne ich, wie z.B task.value, task.style oder bei Objekten mit dem key und den wert car.modell. aber zweimal dasselbe element was bedeutet das?

Code:
<input type="text" value="${task.task}" class="task ${task.completed ? 'completed' : ''}" onfocus="getCurrentTask(this)" onblur="editTask(this)">

2. wenn ich das als if abfrage schreibe ist das dann so richtig von mir, ansonsten verstehe ich das auch nicht :D
Code:
if (task.completed) {
  input.value = task.task.completed
}
else {
  input.value = ''}" onfocus="getCurrentTask(this)" onblur="editTask(this)">
}

3.
Code:
localStorage.setItem("tasks", JSON.stringify([...JSON.parse(localStorage.getItem("tasks") || "[]"), { task: task.value, completed: false }]));

Ist das dasselbe wie

Code:
localStorage.setItem("tasks", JSON.stringify.push(([JSON.parse(localStorage.getItem("tasks") || "[]"), { task: task.value, completed: false }])));

den ternary Operator verstehe ich gar nicht, wie würde der denn als if abrfrage aussehen?

Ab und zu bin ich echt überfordert mit dem Tutorial wenn zuviele verschiedene Zeichenketten hintereinander gereimt werden und nicht zwischendrin beendet werden durch ein ; um eine neue Code Zeile zu starten. Ich bin wieder dankbar für jede Hilfe die ihr mir geben könnt.

Gruß Marc
 
var value = condition ? 'value_if_condition_met' : 'value_if_condition_is_not_met'
=
Code:
var value = 'value_if_condition_is_not_met';
if(condition)
{value = 'value_if_condition_is_met';}
oder
Code:
if(condition)
{var value = 'value_if_condition_is_met';}
else
{var value = 'value_if_condition_is_not_met';}

Zum task Object:
Code:
var task = {
    task: 'Das ist mein Task'
};
console.log(task.task); //'Das ist mein Task'
oder
Code:
var task = {
    task: {
        task: {
            task: 'Das ist mein Task'
};
console.log(task.task.task.task); //'Das ist mein Task'

Das kommt in dem Beispiel auch nur durch tasks.forEach(task => {... weil hier das task Object iterated wird und forEach die einzelnen Elemente von tasks im Loop in der Variable task übergibt.

Öffne mal die Devtools in Chrome oder FF und spiel dich in der Konsole.
 
  • Gefällt mir
Reaktionen: Cark
Vielen Dank euch allen nochmal für eure Hilfe. Ich habe das jetzt so hingekriegt, wie ich es momentan gut nachvollziehen kann.
Javascript:
window.addEventListener('load', () => {
    todos = JSON.parse(localStorage.getItem('todos')) || [];
    const inputField = document.querySelector('#inputField');
    const form = document.querySelector('#form');
    const name = document.querySelector('#name');

    const userName = localStorage.getItem('userName') || '';
    name.value = userName;

    name.addEventListener('change', () => {
        localStorage.setItem('userName', name.value);
    })


    form.addEventListener('submit', e => {
        e.preventDefault();

        const todo = {
            content: inputField.value,
            done: false,
            createdAt: new Date().getTime()
        }

        todos.push(todo);

        localStorage.setItem('todos', JSON.stringify(todos));

        inputField.value = '';

        DisplayTodos()
    })

    DisplayTodos()
})

const filterContainer = document.querySelector('#filterContainer span');

function DisplayTodos () {
    const toDoList = document.querySelector('#toDoList');
    if (todos.length == 0) {
        toDoList.innerHTML =`<li class="text">Du hast noch nichts zum erledigen</li>`;
    }else {
    toDoList.innerHTML = '';
    }
    todos.forEach(todo => {

        const li = document.createElement('li');

        const checkBtn = document.createElement('input');
        const toDoText = document.createElement('input');
        const editBtn = document.createElement('i');
        const deleteBtn = document.createElement('i');

        checkBtn.type = 'checkbox';
        checkBtn.checked = todo.done;
    
        toDoText.classList.add('toDoText');
        checkBtn.classList.add('check');
        editBtn.classList.add('edit');
        deleteBtn.classList.add('delete');

        toDoText.setAttribute('type', 'text');
        toDoText.setAttribute('readonly', '');

        toDoText.value = todo.content;
        editBtn.innerHTML = '&#128393;';
        deleteBtn.innerHTML = '&#128465;';

        li.append(checkBtn, toDoText, deleteBtn, editBtn);

        toDoList.appendChild(li);

        if(todo.done) {
            toDoText.classList.add('done');
        }

        checkBtn.addEventListener('change', () => {
            todo.done = checkBtn.checked;
            localStorage.setItem('todos', JSON.stringify(todos));

            if (todo.done) {
                toDoText.classList.add('done');
            } else {
                toDoText.classList.remove('done');
            }

            DisplayTodos()
        })
        editBtn.addEventListener('click', () => {
            
            toDoText.removeAttribute('readonly');
            toDoText.focus();
            
        toDoText.addEventListener('blur', () => {
            toDoText.setAttribute('readonly', true);
            todo.content = toDoText.value;
            localStorage.setItem('todos', JSON.stringify(todos));
            DisplayTodos()
        })
    })

        deleteBtn.addEventListener('click', () => {
            todos = todos.filter(t => t != todo);
            localStorage.setItem('todos', JSON.stringify(todos));
            DisplayTodos()
        })
    })
}

    const filters = document.querySelectorAll(".filters span");
    
    filters.forEach(filterBtn => {
        
            filterBtn.addEventListener('click', (e) => {

                document.querySelector("span.active").classList.remove("active");
                filterBtn.classList.add("active");
                
                const bla = toDoList.childNodes
                bla.forEach(blub => {
                    switch(e.target.id) {

                        case 'all':
                            blub.style.display = 'list-item';
                            break;

                        case 'completed':
                            if(blub.firstElementChild.checked) {
                                blub.style.display = 'list-item';
                            }else {
                                blub.style.display = 'none';
                            }
                            break;
                            
                        case 'pending':
                            if(blub.firstElementChild.checked) {
                                blub.style.display = 'none';
                            }else {
                                blub.style.display = 'list-item';
                            }
                            break;
                    }
                })       
            })
    });
HTML:
<div id="pageContent">

        <section class="greeting">
            <h2 class="title">
                What's up, <input type="text" id="name" placeholder="Name here" autocomplete="off" />
            </h2>
        </section>

    <form id="form" autocomplete="off">
        <div class="inputBox">
        <input type="text" name="name" required id="inputField">
        <label for="name" class="placeholder">To do einfügen</label>
    </div>
        <button type="submit" id="saveInputBtn">&#128935;</button>
    </form>

    <section id="checkListContainer">

        <h1>Check List</h1>

        <div class="filters">
            <span class="active" id="all">All</span>
            <span id="pending">Pending</span>
            <span id="completed">Completed</span>
          </div>
        
        <ul id="toDoList"></ul>
    </section>

</div>
 
  • Gefällt mir
Reaktionen: Drexel
Das sieht mal ganz ordentlich aus, nur gewöhn dir besser an in deinem Scope zu coden. In Zeile 116 entfernst du die class "active" für alle spans mit der class "active", unabhängig davon, wo sie sich im document befinden. Solltest du einmal Module entwickeln die dynamisch in eine Applikation embedded werden sollen dann schaffst du dir damit einen Haufen Probleme. Wenn du am Anfang noch ein Object mit einem Verweis auf deine Container-Node definierst kannst du alles Nachfolgende darin "sandboxen" und vermeidest Konflikte mit anderem Code.
 
Zurück
Oben