I work on the Kanban board app, it contains three columns for not started, In progress, and Completed tasks, I can add a new task, edit it, delete it, and drag and drop it from column to column. I save all data to local storage, and now I want to retrieve it back when loading the page and add the functionality of the app as it is.
** if any advice to enhance styling when dragging the task to another column as well?
And please if there is any advice to make the code better.
I really appreciate any help you can provide.
I try to set the localStorage.getItem() method but it doesn’t work as I expected
Here’s my code`
HTML
<!DOCTYPE html>
<html lang="en">
<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">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<title>Kanban Board</title>
<script src="script.js" defer></script>
</head>
<body>
<h1>Kanban Board</h1>
<div class="container" id="container">
</div>
<script type="module" src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.js"></script>
</body>
</html>
CSS
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 62.5%;
}
body {
font-family: "Roboto", sans-serif;
background-color: #009578;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
min-height: 100vh;
gap: 6rem;
}
h1 {
font-size: 5rem;
}
h3 {
font-size: 3.5rem;
font-weight: normal;
user-select: none;
}
.container {
display: flex;
align-items: center;
justify-content: space-evenly;
flex-wrap: wrap;
gap: 5rem;
width: 80%;
}
.column,
.tasks {
padding: 1rem 1rem 1rem 0;
display: flex;
flex-direction: column;
gap: 1rem;
width: 30rem;
}
.input-container {
padding: 1rem;
background-color: #fff;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 1rem;
box-shadow: 0 2px 4px rgb(0 0 0 / 20%);
}
.field {
font-size: 1.8rem;
border-radius: 0.4rem;
outline: 0;
border: 0;
}
.icon {
font-size: 2rem;
color: black;
cursor: pointer;
}
.edit {
color: #002d24;
}
.remove {
color: red;
}
.btn {
width: 100%;
padding: 1rem;
font-size: 1.8rem;
background-color: #00866d;
color: #fff;
border: 0;
border-radius: 4px;
cursor: pointer;
box-shadow: 0 2px 4px rgb(0 0 0 / 20%);
}
.btn:hover {
background-color: #006854;
}
JavaScript
const board = document.getElementById("container");
const columns = [
{
id: 1,
title: "Not Started",
},
{
id: 2,
title: "In Progress",
},
{
id: 3,
title: "Completed",
},
];
let drag = null;
// Create Columns and render in page
columns.forEach((column) => {
// Create main column
const columnDiv = document.createElement("div");
columnDiv.className = "column";
columnDiv.id = column.id;
// Create column title
const columnTitle = document.createElement("h3");
columnTitle.textContent = column.title;
columnDiv.appendChild(columnTitle);
// Create tasks lists
const tasksList = document.createElement("ul");
tasksList.className = "tasks";
columnDiv.appendChild(tasksList);
// create add buttons
const addTaskBtn = document.createElement("button");
addTaskBtn.className = "btn";
addTaskBtn.textContent = "+ Add";
columnDiv.appendChild(addTaskBtn);
// evevt listener for buttons to Add A new task
addTaskBtn.addEventListener("click", () => {
const inputContainer = document.createElement("li");
inputContainer.className = "input-container";
inputContainer.draggable = true;
inputContainer.innerHTML = `
<input type='text' class='field' id='${column.title}-task' placeholder='Task'/>
<ion-icon name="pencil-outline" class='icon edit'></ion-icon>
<ion-icon name="trash-outline" class="icon remove"></ion-icon>
`;
tasksList.appendChild(inputContainer);
taskHandlers();
});
board.appendChild(columnDiv);
});
// Update localStorage with html structure
const updateLocalStorage = () => {
localStorage.setItem(
"pageStructure",
document.querySelector(".container").innerHTML,
);
};
// Handle added tasks and control events on it
function taskHandlers() {
const tasks = [...document.querySelectorAll("li")];
tasks.forEach((task) => {
const input = task.querySelector("input");
const editBtn = task.querySelector(".edit");
const deleteBtn = task.querySelector(".remove");
// Save the task
const saveTask = () => {
input.setAttribute("disabled", "");
input.setAttribute("value", input.value);
input.style.cursor = "move";
task.setAttribute("dragable", "true");
updateLocalStorage();
};
// Edit task
const editTask = () => {
input.disabled = false;
input.focus();
input.style.cursor = "auto";
task.removeAttribute("draggable");
updateLocalStorage();
};
// Delete task
const deleteTask = () => {
task.remove();
updateLocalStorage();
};
// Event listneres
input.addEventListener("focusout", () => {
saveTask();
});
input.addEventListener("keypress", (e) => {
if (e.key === "enter") {
saveTask();
}
});
editBtn.addEventListener("click", editTask);
deleteBtn.addEventListener("click", deleteTask);
/*
*****************
// Drag and Drop
*****************
*/
const dragStart = () => {
drag = task;
task.style.opacity = "0.5";
};
const dragEnd = () => {
drag = null;
task.style.opacity = "1";
updateLocalStorage();
};
task.addEventListener("dragstart", dragStart);
task.addEventListener("dragend", dragEnd);
const lists = document.querySelectorAll("ul");
lists.forEach((list) => {
list.addEventListener("dragover", (e) => {
e.preventDefault();
});
list.addEventListener("drop", () => {
list.appendChild(drag);
});
});
});
}
taskHandlers();
2
Answers
You can use
Here is more about localStorage
if you want to get from localStorage and insert inside page use this code: