I am trying to make a logic that if user input, date, and time are not filled it gives the user an alert to have the mentioned sections above, but for some reason, even when I have those sections containing values it still shows null.
The outcome should be:
If there is no value for user input, a due date or time alert should appear.
// variables object
const el = {
form: document.querySelector(".form"),
input: document.querySelector(".user-input"),
list: document.querySelector(".list"),
date: document.querySelector(".date"),
time: document.querySelector(".time")
};
//local storage key
const storage_key = "tasks-storage-key";
//Create ID
const createId = () => `${Math.floor(Math.random() * 10000)}-${new Date().getTime()}`;
//variable of empty array that gets new task
let taskList = [];
// function that renders task list
//function that creates new tasks with date and time
const creatTask = (task) => {
const id = createId();
const taskNew = el.input.value;
const taskDate = el.date.value;
const taskTime = el.time.value;
const tasks = document.createElement("div");
tasks.innerHTML = `
<div class="task-content">
<div class="list-of-task">
<div class="task" data-id="${id}">
<input type="checkbox" class="tick">
<div class="new-task-created">${taskNew}</div>
<label class="due-date">${taskDate}</label>
<label class="due-time">${taskTime}</label>
</div>
<div class="atcion-buttons">
<button class="edit" data-id="">Edit</button>
<button class="delete" data-id="">Delete</button>
</div>
</div>`;
taskList.push(tasks);
console.log(taskList);
el.list.appendChild(tasks);
return task
};
//event listner that listens for add button.
function addTask(taskNew, taskDate, taskTime) {
if (taskNew == null) {
alert("Please add a new Task")
}
if (taskDate == null) {
alert("Please add a new Task with a due date");
}
if (taskTime == null) {
alert("Please add a new Task with a due time");
}
creatTask();
}
<div class="form">
<input class="user-input" type="text">
<input class="date" type="date">
<input class="time" type="time">
<button onclick="addTask()" class="add" id="add">+</button>
</div>
<div class="list"></div>
All values obtained from form elements are strings. Even if the element is empty, the value is still "", not null so checking for null isn't the right approach.
Instead test for the absence of any "truthy" value as seen below.
// variables object
const el = {
form: document.querySelector(".form"),
input: document.querySelector(".user-input"),
list: document.querySelector(".list"),
date: document.querySelector(".date"),
time: document.querySelector(".time")
};
//local storage key
const storage_key = "tasks-storage-key";
//Create ID
const createId = () => `${Math.floor(Math.random() * 10000)}-${new Date().getTime()}`;
//variable of empty array that gets new task
let taskList = [];
// function that renders task list
//function that creates new tasks with date and time
const creatTask = (task) => {
const id = createId();
const taskNew = el.input.value;
const taskDate = el.date.value;
const taskTime = el.time.value;
const tasks = document.createElement("div");
tasks.innerHTML = `
<div class="task-content">
<div class="list-of-task">
<div class="task" data-id="${id}">
<input type="checkbox" class="tick">
<div class="new-task-created">${taskNew}</div>
<label class="due-date">${taskDate}</label>
<label class="due-time">${taskTime}</label>
</div>
<div class="atcion-buttons">
<button class="edit" data-id="">Edit</button>
<button class="delete" data-id="">Delete</button>
</div>
</div>`;
taskList.push(tasks);
console.log(taskList);
el.list.appendChild(tasks);
return task
};
//event listner that listens for add button.
function addTask(taskNew, taskDate, taskTime) {
if (!taskNew) {
alert("Please add a new Task")
}
if (!taskDate) {
alert("Please add a new Task with a due date");
}
if (!taskTime) {
alert("Please add a new Task with a due time");
}
creatTask();
}
<div class="form">
<input class="user-input" type="text">
<input class="date" type="date">
<input class="time" type="time">
<button onclick="addTask()" class="add" id="add">+</button>
</div>
<div class="list"></div>
Thanks for the help.
I also found another way of doing it as well after doing further research.
// variables object
const el = {
form: document.querySelector(".form"),
input: document.querySelector(".user-input"),
list: document.querySelector(".list"),
date: document.querySelector(".date"),
time: document.querySelector(".time")
};
//local storage key
const storage_key = "tasks-storage-key";
//Create ID
const createId = () => `${Math.floor(Math.random() * 10000)}-${new Date().getTime()}`;
//variable of empty array that gets new task
let taskList = [];
// function that renders task list
//function that creates new tasks with date and time
const creatTask = (task) => {
const id = createId();
const taskNew = el.input.value;
const taskDate = el.date.value;
const taskTime = el.time.value;
if (taskNew.length == 0) {
alert("Please add a new Task");
}
if (taskDate.length == 0) {
alert("Please add a new Task with a due date");
}
if (taskTime.length == 0) {
alert("Please add a new Task with a due time");
}
const tasks = document.createElement("div");
tasks.innerHTML = `
<div class="task-content">
<div class="list-of-task">
<div class="task" data-id="${id}">
<input type="checkbox" class="tick">
<div class="new-task-created">${taskNew}</div>
<label class="due-date">${taskDate}</label>
<label class="due-time">${taskTime}</label>
</div>
<div class="atcion-buttons">
<button class="edit" data-id="">Edit</button>
<button class="delete" data-id="">Delete</button>
</div>
</div>`;
taskList.push(tasks);
console.log(taskList);
el.list.appendChild(tasks);
return task
};
//event listner that listens for add button.
function addTask() {
creatTask();
}
<div class="form">
<input class="user-input" type="text">
<input class="date" type="date">
<input class="time" type="time">
<button onclick="addTask()" class="add" id="add">+</button>
</div>
<div class="list"></div>
Related
I know I must do a for each loop so that when a new task is created it adds the new task to the array and not replace the current one.
Currently my addEventListener is only creating a task.
let listArray = []
let date = Date.now()
let id = Math.floor((Math.random() + date) * 3000)
let add = document.querySelector("#add")
add.addEventListener("click", (event) => {
let input = document.querySelector("#User-Input input")
let list = document.querySelector(".list")
list.classList.add("todo")
list.innerHTML = `
<div data-type="${id}"></div>
<p>${input.value}</p>
`
listArray.push(list)
})
<div class="container">
<div id="User-Input">
<input id="text-area" type="text">
<button id="add">Add</button>
</div>
<div class="list">
</div>
Instead of overwriting list.innerHTML, you can append to it:
let listArray = []
let date = Date.now()
let id = Math.floor((Math.random() + date) * 3000)
let add = document.querySelector("#add")
add.addEventListener("click", (event) => {
let input = document.querySelector("#User-Input input")
let list = document.querySelector(".list")
list.classList.add("todo")
// HERE!
list.innerHTML += `
<div data-type="${id}"></div>
<p>${input.value}</p>
`
listArray.push(list)
})
<div class="container">
<div id="User-Input">
<input id="text-area" type="text">
<button id="add">Add</button>
</div>
<div class="list">
</div>
You don't need a loop (or the array for that matter). At the moment you're replacing the HTML of the list element rather than adding to it. You can use insertAdjacentHTML for that. It gives you the option of where to add the new HTML - here we're using beforeend.
Note you can cache all of your elements outside of the handler, but you should add the code that creates the id inside the handler (or add it to a separate function which is called in the handler) so that the id is different for each new todo.
(In this example I'm also emptying the input box after each submission, and refocusing the cursor in the box ready for the next entry.)
const input = document.querySelector('#User-Input input');
const list = document.querySelector('.list');
const add = document.querySelector('#add')
input.focus();
add.addEventListener("click", (event) => {
const date = Date.now();
const id = Math.floor((Math.random() + date) * 3000);
const html = `
<div class="todo" data-id="${id}">
<p>${input.value}</p>
</div>
`;
list.insertAdjacentHTML('beforeend', html);
input.value = '';
input.focus();
});
.list { width: 80%; }
.todo { background-color: #efefef;}
.todo p { padding: 0.25em; }
<div class="container">
<div id="User-Input">
<input id="text-area" type="text">
<button id="add">Add</button>
</div>
<div class="list"></div>
</div>
I have already found a way to get what I want, but I'm trying to understand why the next code doesn't work.
If to be more precise why does the function showHideTaskDetails() doesn't seem to do what it should do (BTW leave aside its name, it's not an indication of its purpose)
I expect the following to happen:
When clicking on the button with the class "fa-solid fa-circle-chevron-down", the value of the variable hideContent change to the opposite of the current value (if it's true to become false and vice versa).
After that if the hideContent is true the variable color will be "background-color: red" so the style of all dives will change to have background with the color red.
But instead, nothing happens!
HTML
<body>
<div class="container">
<form action="">
<label for="task-headline">Task Headline</label>
<input type="text" id="task-headline">
<label for="deadline">Task Deadline</label>
<input type="date" id="deadline">
<label for="task-details">Task Details</label>
<textarea name="" id="task-details" cols="80" rows="10"></textarea>
<button id="add-task">Add Task</button>
</form>
<div class="tasks-area"></div>
</div>
</body>
JS
const headLineEl = document.getElementById("task-headline")
const deadlineEl = document.getElementById("deadline")
const taskDetailsEl = document.getElementById("task-details")
const TasksAreaEl = document.querySelector(".tasks-area")
addTaskBtn = document.getElementById("add-task")
let hideContent = true
let color = ""
showTasks()
addTaskBtn.addEventListener("click", (e) => {
e.preventDefault()
const newTask = collectTaskInfo()
saveToLs(newTask)
showTasks()
})
//get from the local storage the current tasks
function getLsData() {
let currentLsContent = JSON.parse(localStorage.getItem("tasks"))
if (currentLsContent === null) {
currentLsContent = []
}
return currentLsContent
}
//show the tasks on the dom
function showTasks() {
const array = getLsData()
let tasksContainer = []
array.map(task => {
const readyTask =
`
<div class="task-container" style=${color}>
<div class="main-basic-info">
<p> <span>Task:</span> ${task.headline} </p>
<div class="left-part">
<p> <span>Deadline:</span> ${task.deadline} </p>
<i class="fa-solid fa-circle-chevron-down" onClick="showHideTaskDetails()"></i>
</div>
</div>
<p class="details"> <span>Details:</span> ${task.details} </p>
</div>
<br>
`
tasksContainer.push(readyTask)
})
TasksAreaEl.innerHTML = tasksContainer
}
//hide unhide details
function showHideTaskDetails() {
hideContent = !hideContent
console.log(hideContent);
if (hideContent) color = "background-color: red"
// const test = document.getElementsByTagName('div')
// test.style = "background-color: red"
}
//collect task information to object
function collectTaskInfo() {
const obj = {
headline: headLineEl.value,
deadline: deadline.value,
details: taskDetailsEl.value
}
return obj
}
//update the current array in local storage with the new task
function addNewTaskToLsArray(newTask) {
const currentTaskArrayInLs = getLsData()
currentTaskArrayInLs.push(newTask)
const updatedTaskArray = currentTaskArrayInLs
return updatedTaskArray
}
//save data to local storage
function saveToLs(task) {
const arrayWithTheNewTask = addNewTaskToLsArray(task)
localStorage.setItem("tasks", JSON.stringify(arrayWithTheNewTask))
}
You showHideTasksDetails function is not re-rendering the page by itself.
You can modify it so that the showTasks function is called again when the showHideTaskDetails is called.
function showHideTaskDetails() {
hideContent = !hideContent;
console.log(hideContent);
if (hideContent) {
color = "'background-color: red'";
} else {
color = "";
}
// const test = document.getElementsByTagName('div')
// test.style = "background-color: red"
showTasks();
}
first it's onclick not onClick
Second initial value of hideContent is set to true and you're changing it to false when you're calling the showHideTaskDetails fn before if statement
I am trying to make the list stay on the page when the browser refreshes, I did ask this question before, but I am a bit confused about what exactly should I do or how should I update my code to get it right.
Here is a link to my original question original question
They mentioned a forEach loop should be used, which I have been trying but it is not working
//variable of empty array that gets new task
let taskList = [];
//function that creates new tasks with date and time
const creatTask = (task) => {
const data = {
id: createId(),
taskNew: el.input.value,
taskDate:el.date.value,
taskTime: el.time.value,
}
if (!data.taskNew) {
alert("Please add a new Task");
}
if (!data.taskDate) {
alert("Please add a new Task with a due date");
}
if (!data.taskTime) {
alert("Please add a new Task with a due time");
}
const tasks = document.createElement("div");
tasks.innerHTML = `
<div class="task-content">
<div class="task" data-id="${data.id}">
<div class="new-task-created">${data.taskNew}</div>
<label class="due-date">${data.taskDate}</label>
<label class="due-time">${data.taskTime}</label>
</div>
<div class="atcion-buttons">
<button onclick="editItem()" class="edit" data-id="${data.id}">Edit</button>
<button onclick="deleteItem()" class="delete" data-id="${data.id}">Delete</button>
<button onclick="completeItem()" class="complete" data-id="${data.id}">Complete</button>
</div>
</div>`;
taskList.push(data);
el.list.appendChild(tasks);
storeList();
};
//function that stores task list.
function storeList() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(taskList));
}
// Add tasks to my todo list
let inputTask = document.getElementById('add-task').value;
let inputStatus = document.getElementById('add-status').value;
const addtasks = document.getElementById('task-add-btn').addEventListener('click', (event)=>{
let newEntry = {
title : inputTask,
status : inputStatus
}
console.log(newEntry);
});
<input type='text', id='add-task', placeholder="Add TODO Task">
<input type="text", id ='add-status', placeholder="Status True/False">
<div id="task-add">
<button id='task-add-btn' class="btn">Add Tasks</button>
</div>
Here I want to access values in the input field. But I am getting results as empty strings. Can Someone help??
You are storing the values of the inputs before anything has been typed into them. You need to get the values when the button is clicked.
// Add tasks to my todo list
let inputTask = document.getElementById('add-task');
let inputStatus = document.getElementById('add-status');
const addtasks = document.getElementById('task-add-btn').addEventListener('click', (event)=>{
let newEntry = {
title : inputTask.value,
status : inputStatus.value
}
console.log(newEntry);
});
<input type='text', id='add-task', placeholder="Add TODO Task">
<input type="text", id ='add-status', placeholder="Status True/False">
<div id="task-add">
<button id='task-add-btn' class="btn">Add Tasks</button>
</div>
value is in the wrong place.
// Add tasks to my todo list
const inputTask = document.getElementById('add-task')
const inputStatus = document.getElementById('add-status')
const addtasks = document.getElementById('task-add-btn').addEventListener('click', (event)=>{
let newEntry = {
title : inputTask.value,
status : inputStatus.value,
}
console.log(newEntry);
});
<input type='text', id='add-task', placeholder="Add TODO Task">
<input type="text", id ='add-status', placeholder="Status True/False">
<div id="task-add">
<button id='task-add-btn' class="btn">Add Tasks</button>
</div>
I am working on a very basic task application with vanilla javascript. I have an array and from that, I am rendering the todos dynamically. I want to delete a todo when the checkbox is clicked.
I tried to create a form with the id of the todo in the hidden input and on change event submit the form and delete the todo but I'm generating all of them dynamically. Don't you think it will be a lot of code?
Is there a better way to do this?
Thank you
const todos = ['Complete the todo app', 'Write a script', 'Record a video', 'Publish the video']
const renderTodos = function (todos) {
document.querySelector('#todos').innerHTML = ''
todos.forEach(function (todo, index) {
const divElem = document.createElement('div')
divElem.classList.add(`item`, `item-${index}`)
document.querySelector('#todos').appendChild(divElem)
const checkboxElem = document.createElement('input')
checkboxElem.type = 'checkbox'
checkboxElem.name = 'deleteTodo'
document.querySelector(`.item-${index}`).appendChild(checkboxElem)
const titleElem = document.createElement('p')
titleElem.textContent = todo
document.querySelector(`.item-${index}`).appendChild(titleElem)
})
}
renderTodos(todos)
document.querySelector('#add-todo').addEventListener('submit', function (e) {
e.preventDefault()
if (e.target.elements.newItem.value === '') {
return
}
todos.push(e.target.elements.newItem.value)
e.target.elements.newItem.value = ''
renderTodos(todos)
})
<div id="todos"></div>
<form class="item" id="add-todo" action="">
<input
type="text"
name="newItem"
placeholder="New Item"
autocomplete="off"
/>
<button type="submit" name="list">+</button>
</form>
use remove method :
const DomParser = new DOMParser()
, todoAll = document.getElementById('todos')
, todoForm = document.getElementById('add-todo')
, todos = ['Complete the todo app', 'Write a script', 'Record a video', 'Publish the video']
;
function todoAdding(todo, index)
{
let elmZ = `<div class="item item-${index}"><input type="checkbox" name="deleteTodo"><p>${todo}</p></div>`;
let inZ = DomParser.parseFromString( elmZ, 'text/html');
todoAll.appendChild( inZ.body.firstChild )
}
function renderTodos(todos)
{
document.querySelector('#todos').innerHTML = ''
todos.forEach( todoAdding )
}
todoForm.onclick = e =>
{
e.preventDefault()
if (todoForm.newItem.value === '') return
todos.push(todoForm.newItem.value)
todoForm.newItem.value = ''
renderTodos(todos)
}
todoAll.onclick = e =>
{
if (!e.target.matches('input[type=checkbox]')) return
let suppIndex = todos.findIndex(todo=>todo===e.target.parentNode.querySelector('p').textContent)
todos.splice(suppIndex,1)
e.target.parentNode.remove()
}
renderTodos(todos) // initial case
<div id="todos"></div>
<form class="item" id="add-todo" action="">
<input
type="text"
name="newItem"
placeholder="New Item"
autocomplete="off"
/>
<button type="submit" name="list">+</button>
</form>