I'm trying to improve the code of my first project which is to do list
using fontawesome icons . In each item I have, among other things, a button that serves to mark whether the task is completed or not. This button appears with a default icon that is stored in the variable in the code CIRCLE_INCON
, but what I want is that when the task is completed it changes to another icon that is stored in the variable CHECK_ICON
. What I did is the following (I only show the parts of the code related to the button to complete the task that I call checkBtn
):
//ICONS
const CIRCLE_INCON = `<i class="far fa-circle fa-lg"></i>`;
const CHECK_ICON = `<i class="far fa-check-circle fa-lg"></i>`;
//LOS "..." SIGNIFICAN QUE HAY CODIGO ANTES DE ESO
//PUEDEN VER ABAJO EL CODIGO COMPLETO
function addTask(fromList){
//...
//CREATING COMPONENTS
const checkBtn= document.createElement("button");
//...
//SUB-COMPONENT CHECKBOX
checkBtn.classList.add("checkbox");
checkBtn.innerHTML = CIRCLE_INCON;
checkBtn.value= "not-checked";
//...
//ASI ES COMO LLAMO A LA FUNCION QUE SE ENCARGA DE CHEQUEAR O COMPLETAR LA TAREA
item.addEventListener("click", (element) => {
element = element.target;
let circleClass = element.classList.contains("fa-circle")
let checkClass= element.classList.contains("fa-check-circle");
(circleClass || checkClass) ? checkTask() : false;
});
//CHECK THE TASK
function checkTask (){
//SI EL VALOR DEL CHECKBUTTON NO ESTA CHEQUEADO EJECUTA LA FUNCION COMPLETEDTASK()
checkBtn.value ==="not-checked" ? completedTask(): incompletedTask();
function completedTask() {
checkBtn.setAttribute("value","checked");
checkBtn.innerHTML = CHECK_ICON;
saveValue(checkBtn, CHECK_ICON);
}
function incompletedTask() {
checkBtn.setAttribute("value","not-checked");
checkBtn.innerHTML = CIRCLE_INCON;
saveValue(checkBtn, CIRCLE_INCON);
}
//ACA ES COMO GUARDO EL VALOR DE COMPLETED AL LOCALSTORAGE
function saveValue(el, icon){
const dataLS = JSON.parse(localStorage.getItem('item.list'));
dataLS[id].completed = el.value;
dataLS[id].icon = icon
el.innerHTML = dataLS[id].icon; //AQUI ES COMO INTENTE GUARDAR EL ICONO AL LOCALSTORAGE
localStorage.setItem('item.list', JSON.stringify(dataLS));
}
toDoTxt.classList.toggle("completed");
};
So the code works exactly as I want but what I want is to simplify the function checkTask()
using .toggle()
something like this:
//PRIMERO CAMBIO DE TAG DE "button" A UN "i"
const checkBtn= document.createElement("i");
//CHECK THE TASK
function checkTask (){
//SI EL VALOR DEL CHECKBUTTON NO ESTA CHEQUEADO EJECUTA LA FUNCION COMPLETEDTASK()
checkBtn.classList.toggle("fa-circle");
checkBtn.classList.toggle("fa-check-circle");
toDoTxt.classList.toggle("completed");
//ACA ES COMO GUARDO EL VALOR DE COMPLETED AL LOCALSTORAGE
function saveValue(el, icon){
const dataLS = JSON.parse(localStorage.getItem('item.list'));
dataLS[id].completed = el.value;
dataLS[id].icon = icon
el.innerHTML = dataLS[id].icon; //AQUI ES COMO INTENTE GUARDAR EL ICONO AL LOCALSTORAGE
localStorage.setItem('item.list', JSON.stringify(dataLS));
}
};
But the problem is that when I do that, the icon does not appear, but a square appears. If anyone knows what's going on, please explain to me, I'd really appreciate it. Below I leave the complete code so you can see how it is composed.
const form = document.getElementById("list");
const input = document.getElementById("input");
const normalButton = document.getElementById("normal");
const finishedTask = document.getElementById("done");
const unfinishedTask = document.getElementById("not-done");
const refreshBtn = document.getElementById("refresh-btn");
const failBox = document.getElementById("fail");
const closeBtn = document.getElementById("close-btn");
const taskCategories = document.getElementById("categories")
//ICONS
const CIRCLE_INCON = `<i class="far fa-circle fa-lg"></i>`;
const CHECK_ICON = `<i class="far fa-check-circle fa-lg"></i>`;
const TRASH_ICON = `<i class="fas fa-trash-alt"></i>`;
const EDIT_ICON =`<i class="far fa-edit"></i>`;
let lists = [];
document.addEventListener("keyup",(event)=>{ if(event.keyCode === 13) addTask() });
refreshBtn.addEventListener("click",() => refreshPage());
// Obtener desde localStorage al cargar todo el DOM
window.addEventListener('load', function() {
lists = JSON.parse(localStorage.getItem("item.list")) || [];
// Agregar en HTML los elementos encontrados
lists.forEach((item) => addTask(item));
});
function addTask(fromList){
event.preventDefault();
let inputValue= (fromList) ? fromList.name : input.value;
if(inputValue === "" || inputValue === null) return failAlert();
function failAlert(){
failBox.style.display = "block";
closeBtn.addEventListener("click", ()=> failBox.style.display = "none")
}
//CREATING COMPONENTS
const item = document.createElement("li");
const deleteBtn = document.createElement("button");
const toDoTxt = document.createElement("p");
const editBtn = document.createElement("button");
const checkBtn= document.createElement("i");
const btnContainer = document.createElement("div");
btnContainer.classList.add("buttons");
//ITEM COMPONENT
item.classList.add("item");
let id = item.dataset. id;
id = (fromList) ? fromList.id : lists.length;
//APPEND COMPONENTS TO THE ITEM
item.appendChild(checkBtn);
item.appendChild(toDoTxt);
form.appendChild(item);
item.appendChild(btnContainer);
//SUB-COMPONENT TODO
toDoTxt.classList.add("text");
const text= document.createTextNode(inputValue);
toDoTxt.appendChild(text);
//SUB-COMPONENT CHECKBOX
checkBtn.classList.add("checkbox");
checkBtn.innerHTML = CIRCLE_INCON;
checkBtn.value= "not-checked";
//SUB-COMPONENT EDIT BUTTON
editBtn.classList.add("edit");
editBtn.innerHTML = EDIT_ICON;
btnContainer.appendChild(editBtn);
//SUB COMPONENT DELETE BUTTON
deleteBtn.classList.add("delete");
deleteBtn.innerHTML = TRASH_ICON;
btnContainer.appendChild(deleteBtn);
item.addEventListener("click", (element) => {
element = element.target;
let circleClass = element.classList.contains("fa-circle")
let checkClass= element.classList.contains("fa-check-circle");
let trashClass = element.classList.contains("fa-trash-alt");
let editClass = element.classList.contains("fa-edit");
(circleClass || checkClass) ? checkTask() : false;
(trashClass) ? deleteTask() : false;
(editClass) ? editTask() : false;
});
//CHECK THE TASK
function checkTask (){
//SI EL VALOR DEL CHECKBUTTON NO ESTA CHEQUEADO EJECUTA LA FUNCION COMPLETEDTASK()
checkBtn.value ==="not-checked" ? completedTask(): incompletedTask();
checkBtn.classList.toggle("fa-circle");
checkBtn.classList.toggle("fa-check-circle");
function completedTask() {
checkBtn.setAttribute("value","checked");
checkBtn.innerHTML = CHECK_ICON;
saveValue(checkBtn, CHECK_ICON);
}
function incompletedTask() {
checkBtn.setAttribute("value","not-checked");
checkBtn.innerHTML = CIRCLE_INCON;
saveValue(checkBtn, CIRCLE_INCON);
}
//ACA ES COMO GUARDO EL VALOR DE COMPLETED AL LOCALSTORAGE
function saveValue(el, icon){
const dataLS = JSON.parse(localStorage.getItem('item.list'));
dataLS[id].completed = el.value;
dataLS[id].icon = icon
el.innerHTML = dataLS[id].icon; //AQUI ES COMO INTENTE GUARDAR EL ICONO AL LOCALSTORAGE
localStorage.setItem('item.list', JSON.stringify(dataLS));
}
toDoTxt.classList.toggle("completed");
};
// EDIT THE TASK
function editTask (){
//ACA YO ES DONDE EDITO LAS TAREAS
toDoTxt.innerHTML = `<div class=".edit-container" id = "edit-container"></div>`;
let editContainer = document.getElementById("edit-container");
let editInput = document.createElement("input");
let submitEdit = document.createElement("button");
editInput.classList.add("edit-input");
submitEdit.classList.add("submit-edit");
submitEdit.innerHTML = `<i class="fas fa-plus-circle fa-lg"></i>`
editContainer.appendChild(editInput);
editContainer.appendChild(submitEdit);
submitEdit.addEventListener("click",() => editTask());
//ACA ES COMO GUARDO EL NUEVO NOMBRE EDITADO AL LOCALSTORAGE
function saveNewTask(){
const dataLS = JSON.parse(localStorage.getItem('item.list'));
dataLS[parseInt(id)].name = editInput.value;
localStorage.setItem('item.list', JSON.stringify(dataLS));
}
function editTask (){
toDoTxt.innerHTML = editInput.value;
saveNewTask();
};
};
//DELETE THE TASK
function deleteTask (){
//DONDE ELIMINO LAS TAREAS
const dataLS = JSON.parse(localStorage.getItem('item.list'));
form.removeChild(item);
deleteBtn.parentNode.parentNode
dataLS.splice(dataLS.id, 1);
localStorage.setItem('item.list', JSON.stringify(dataLS));
};
taskCategories.addEventListener("click", (element) => {
element = element.target;
console.log(element);
if (element === normalButton) return goToNormal();
if (element === finishedTask) return seeFinishedTasks();
if (element === unfinishedTask) return seeUnfinishedTask();
});
let goToNormal = () => item.style.display = "flex";
let seeFinishedTasks = () => {
checkBtn.value==="checked" ? item.style.display = "flex" : item.style.display = "none";
};
let seeUnfinishedTask = () => {
checkBtn.value==="not-checked" ? item.style.display = "flex" : item.style.display = "none";
};
//UPLOADING THE DATA
let data = createDataList(inputValue, checkBtn.value, CIRCLE_INCON);
if(!fromList) {
lists.push(data);
save();
}
function save(){
localStorage.setItem("item.list", JSON.stringify(lists));
}
function createDataList(name, completed, icon){
return {id: lists.length, name: name, completed: completed, icon: icon};
}
input.value = "";
}
function refreshPage(){
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="css/style.css">
<link href="https://fonts.googleapis.com/css?family=Roboto+Slab&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:300&display=swap" rel="stylesheet">
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<title>To Do List</title>
</head>
<body>
<div class="container">
<div class="header">
<i class="fas fa-sync-alt" id="refresh-btn"></i>
<div class="title-container">
<h1 class="title">To Do List App</h1>
</div>
<div class="date" id="date"></div>
<div class="categories" id="categories">
<button id="normal" class="normal">NORMAL</button>
<button id="done" class="done">DONE</button>
<button id="not-done" class="not-done">NOT-DONE</button>
</div>
</div>
<div class="fail" id="fail">
<i class="fas fa-times-circle" style="color: #fff;" id="close-btn"></i>
<p class="failed-text">Please type a valid to do</p>
</div>
<div class="content">
<ul id="list" class="list"></ul>
</div>
<div class="add-item">
<input type="text" class="input" id="input" placeholder="Add something to do">
<i class="fas fa-plus-circle fa-lg" id="button" onclick="addTask()"></i>
</div>
</div>
<script defer src="https://kit.fontawesome.com/09faf5376a.js" crossorigin="anonymous"></script>
<script defer src="app.js/app.js"></script>
</body>
</html>
For fontawesome to work several things need to be correct. 1. That the url of the library is correctly embedded
The element that will contain the typography (the icon) must contain the class fa and the class of the specific icon
class="fa fa-check-circle"
All icons contain fa-iconname 3. In some cases, embedding only one library like "regular" causes you to use other types of classes, for example
In all cases, for an icon to be displayed, you just have to change and add the classes of the icon in question.
The "squares" issue is due to the fact that the typeface that fontawesome is composed of (hence its name "Font incredible") is not loading correctly. Check the browser console and verify that there are no 404 errors (This would indicate that you added the url but it is not correct or the file does not exist).
On the other hand, it would be better if you add more information and the code you use in the html.
You have to first add the class
far
orfas
to the elementi
after creating it. Without that, a box will appear and not the icon when you try to change it.The fix would look like this:
I hope it helps you.