I wrote my first web app. Please let me know what I should improve. I want to write as clean code as possible.
App is about adding and removing tasks from list. Backend is written in Django, frontend in Sass and JavaScript.
Below my code for items view. Whole project can be seen in link:
Demo:
Code for items view:
- JavaScript
- Sass
- HTML
// Start with first item
let counter = 0;
// Load 6 items at a time
const QUANTITY_START = 6;
const QUANTITY_TO_ADD_ON_SCROLL = 3;
let isListEmpty = true;
let removed = [];
let areMoreItems = true;
const HIDE_ANIMATION_DURATION_OPACITY = 1500
document.addEventListener('DOMContentLoaded', () => {
// SETTING LISTENERS:
window.onscroll = () => {
if (areMoreItems && isScrolledToBottom()){
const scroll = window.onscroll;
window.onscroll = "none";
load(QUANTITY_TO_ADD_ON_SCROLL);
setTimeout(() => {
window.onscroll = scroll;
}, 1000);
}
}
deleteItemListener();
confirmDeleteButtonListener();
// END OF SETTING LISTENERS
load(QUANTITY_START);
})
function confirmDeleteButtonListener() {
const confirm_button = document.querySelector(".confirm-delete-button");
confirm_button.addEventListener("click", () => {
confirm_button.value = removed.join();
})
}
function deleteItemListener() {
document.querySelector(".main").addEventListener("click", function(event) {
if(event.target.nodeName === "I") {
const itemElement = event.target.parentElement.parentElement;
const item_id = itemElement.querySelector('.id').innerHTML;
removed.push(item_id);
itemElement.style.animationPlayState = 'running';
// itemElement.addEventList;
document.querySelector(".confirm-delete-button").disabled = false;
}
});
}
function isScrolledToBottom() {
return window.innerHeight + window.scrollY >= document.body.offsetHeight
}
function load(quantity) {
const start = counter;
const end = start + quantity - 1;
counter = end + 1;
fetch(`itemslist?start=${start}&end=${end}`)
.then(response => response.json())
.then(data => {
if (data.itemslist.length > 0) {
isListEmpty = false;
data.itemslist.forEach(addItem);
} else {
areMoreItems = false;
if (isListEmpty) {
addEmptyListInfo();
}
}
});
}
function addEmptyListInfo() {
const item = document.createElement('section');
item.className = "empty-list";
item.innerText = "Your list is empty";
document.querySelector('.main-items').append(item)
}
function addItem(item) {
const itemNode = document.createElement('section');
itemNode.className = "todo-item";
itemNode.innerHTML =
`<p hidden class="id">${item.id}</p>
<div name="delete-button" value="${item.id}" class="x-wrapper">
<i class="far fa-times-circle"></i>
</div>
<h2 name="name" class="todo-item-name">${item.name}</h2>
<label for="details">Details:</label>
<p class="details" name="details">${item.details}</p>
<p class="date">Deadline: ${item.date}</p>`;
document.querySelector('.main-items').append(itemNode);
};
.nav {
.li {
background-color: transparent;
border: none;
cursor: pointer;
font-family: 'Caveat', cursive;
color: #fff;
outline: none;
}
form {
display: flex;
display: -webkit-box;
display: -ms-flexbox;
flex-direction: row;
}
}
.main-items {
opacity: 0.9;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
flex-direction: row !important;
justify-content: space-evenly;
flex-wrap: wrap;
.todo-item {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
color: #000;
height: 300px;
width: 400px;
padding: 20px;
margin: 0 15px;
position: relative;
-webkit-animation-name: hide;
animation-name: hide;
-webkit-animation-duration: 1.5s;
animation-duration: 1.5s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
-webkit-animation-play-state: paused;
animation-play-state: paused;
background-image: url(../img/sticky1.png);
background-size: 400px 300px;
line-height: 100%;
.todo-item-name {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: flex-start;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
margin-bottom: 10px;
margin-left: 40px;
margin-right: 25px;
height: 40px;
font-size: 25px;
font-weight: bold;
margin-top: 20px;
padding: 5px;
outline: none;
color: #000;
overflow-y: auto;
scrollbar-width: thin;
scroll-padding: 0;
scroll-margin: 0;
white-space: nowrap;
cursor: default;
}
.details {
border-radius: 5px;
overflow-wrap: break-word;
overflow-y: auto;
height: 100px;
padding: 10px;
margin-left: 40px;
margin-right: 25px;
text-align: justify;
resize: none;
margin-bottom: 10px;
outline: none;
font-size: 22px;
scrollbar-width: thin;
scroll-padding: 0;
scroll-margin: 0;
cursor: default;
}
.x-wrapper {
position: absolute;
right: 0;
top: 0;
margin: 10px;
font-size: 20px;
-webkit-transition: all 0.2s;
transition: all 0.2s;
cursor: pointer;
border: none;
color: #e9c1c1;
background-color: transparent;
}
.x-wrapper:hover {
color: #fff;
}
}
.empty-list {
font-size: 44px;
margin-bottom: 40px;
background-color: rgba(0, 0, 0, 0.5);
padding: 10px;
padding-right: 15px;
border-radius: 10px;
text-align: center;
pointer-events: none;
}
.todo-item label {
font-size: 20px;
margin-bottom: 2px;
margin-left: 40px;
margin-right: 25px;
}
.date {
text-align: right;
margin-right: 25px;
pointer-events: none;
}
}
@-webkit-keyframes hide {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes hide {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
{% extends "TodoListApp/base.html" %}
{% load static %}
{% block style %}
<link rel="stylesheet" href="{% static 'TodoListApp/css/items.css' %}">
<link rel="stylesheet" href="{% static 'TodoListApp/css/loader.css' %}">
<title>Items</title>
{% endblock %}
{% block body %}
<div id="loader-wrapper">
<div id="loader"></div>
<div class="section-left"></div>
<div class="section-right"></div>
</div>
<nav class="nav">
<a href="{% url 'newitem' %}">
<div class="li">Add new item</div>
</a>
<form action="{% url 'items' %}" method="post">
{% csrf_token %}
<button class="add-10-items li" value="add-10-items" name="add-10-items">add 10 items</button>
<button disabled class="confirm-delete-button li" value="" name="confirm-delete-button">confirm deleting</button>
</form>
<a href="{% url 'logout' %}">
<div class="li">Logout</div>
</a>
</nav>
<div class="container container-items">
<header class="header">
<h1>Hello :{{ name }}:</h1>
<h1>Here is a list of your activities:</h1>
</header>
<main class="main main-items">
</main>
</div>
<script src="{% static 'TodoListApp/js/items.js' %}"></script>
<script src="{% static 'TodoListApp/js/loader.js' %}"></script>
{% endblock %}