Skip to main content
Code Review

Return to Question

Tweeted twitter.com/StackCodeReview/status/1453511933739642883
edited tags
Link
Bumped by Community user
Source Link

Simple Vanilla JS Todo app

I'm a Kotlin engineer looking to get into web dev. I thought it'd be fun to make a Todo app w/o help from the internet. Just looking for some critiques and feedback, as I'm new-ish to the language.

Here's the JS, HTML, CSS. Looking for criticism on all of it. No mobile support btw.

JS:

class Column {
 
 constructor(elementId, countId) {
 this.items = new Map();
 this.count = this.items.size;
 this.elementId = elementId;
 this.countId = countId;
 this.node = document.getElementById(this.elementId);
 this.countNode = document.getElementById(this.countId);
 }
 updateCount() {
 this.count = this.items.size;
 this.countNode.innerHTML = "|(" + this.count.toString() + ")";
 }
}
class Todo extends Column {
 constructor() {
 super("todo", "todoCount");
 }
 add(item) {
 item.toolbar.appendChild(item.close);
 if (item.complete) {
 item.checkbox.addEventListener("click", () => {
 closeItem(item);
 });
 item.complete = false;
 }
 this.items.set(item, item.node);
 this.node.appendChild(item.node);
 this.updateCount()
 }
 remove(item) {
 this.items.delete(item);
 item.node.remove();
 item.complete = true;
 this.updateCount();
 }
}
class Done extends Column {
 constructor() {
 super("done", "doneCount");
 }
 add(item) {
 item.checkbox.addEventListener("click", () => {
 openItem(item);
 });
 this.items.set(item, item.node);
 this.node.appendChild(item.node);
 this.updateCount();
 }
 remove(item) {
 this.items.delete(item);
 item.node.remove();
 this.updateCount();
 }
}
class TodoItem {
 constructor() {
 this.node = null;
 this.toolbar = null;
 this.checkbox = null;
 this.close = null;
 this.complete = false;
 }
 generateName() {
 return Math.floor(Math.random() * 1000).toString();
 }
 create() {
 // Create the parent of the todo item
 let item = document.createElement("article");
 item.id = this.generateName();
 // Create a checkbox, and its parent
 let todoToolbar = document.createElement("span");
 todoToolbar.className = "todoToolbar";
 let checkbox = document.createElement("input");
 checkbox.className = "checkbox";
 checkbox.type = "checkbox";
 let close = document.createElement("span");
 close.className = "close"
 close.textContent = "✖";
 // Create the Todo input area
 let input = document.createElement("textarea");
 input.className = "todoInput";
 checkbox.addEventListener("click", () => {
 closeItem(this);
 });
 close.addEventListener("click", () => {
 deleteItem(this);
 });
 // Assign children and set the node
 todoToolbar.appendChild(checkbox);
 todoToolbar.appendChild(close);
 item.appendChild(todoToolbar);
 item.appendChild(input);
 this.node = item;
 this.toolbar = todoToolbar;
 this.checkbox = checkbox;
 this.close = close;
 }
}
let todo = new Todo();
let done = new Done();
function closeItem(item) {
 todo.remove(item);
 done.add(item);
}
function openItem(item) {
 done.remove(item);
 todo.add(item);
}
function deleteItem(item) {
 if (done.items.has(item)) {
 done.items.delete(item);
 done.updateCount();
 }
 if (todo.items.has(item)) {
 todo.items.delete(item);
 todo.updateCount();
 }
 item.node.remove();
}
function createItem() {
 let item = new TodoItem();
 item.create();
 todo.add(item);
}
function main() {
 document.getElementById("addTodo").onclick = createItem;
 todo.updateCount();
 done.updateCount();
}
main();

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <link rel="stylesheet" href="index.css">
 <title>Title</title>
</head>
<body>
 <main id="todoParent">
 <article id="functionality">
 <section id="toolbar">
 <button id="addTodo">Add Todo</button>
 </section>
 <section id="columns">
 <section id="todo">
 <div class="columnToolbar">
 <h1>Todo</h1>
 <h1 id="todoCount"></h1>
 </div>
 </section>
 <section id="done">
 <div class="columnToolbar">
 <h1>Done</h1>
 <h1 id="doneCount"></h1>
 </div>
 </section>
 </section>
 </article>
 </main>
 <script src="index.js"></script>
</body>
</html>

CSS:

html {
 min-height: 100%;
 position: relative;
}
body {
 height: 100%;
}
button {
 z-index: 10;
}
#todoParent {
 display: flex;
 justify-content: center;
 height: 100%;
 top:0;
 bottom:0;
 left:0;
 right:0;
 overflow:hidden;
 background-color: darkslategray;
 position:absolute;
}
#functionality {
 width: 40%;
 background-color: white;
}
#columns {
 display: flex;
 flex-direction: row;
 justify-content: center;
}
#columns h1 {
 text-align: center;
}
#columns section {
 background-color: #e0e0e0;
 border: black solid 1px;
 width: 250px;
 height: 90vh;
 margin: 5%;
 overflow-y: scroll;
}
#columns article {
 display: flex;
 flex-direction: column;
 justify-content: flex-start;
 background-color: white;
 width: 200px;
 height: 200px;
 margin: 5%;
 padding: 5%;
}
#toolbar {
 display: flex;
 justify-content: center;
 flex-direction: row;
 background-color: #e0e0e0;
}
#toolbar button {
 margin: 5px;
}
#todoCount {
 margin-left: 1%;
}
.todoToolbar {
 display: flex;
 flex-direction: row;
 justify-content: space-between;
}
.todoCheckbox {
 margin: 5%;
}
.todoInput {
 height: 100%;
 box-sizing: border-box;
 resize: vertical;
}
.columnToolbar {
 display: flex;
 flex-direction: row;
 justify-content: center;
}
```
lang-css

AltStyle によって変換されたページ (->オリジナル) /