I am very new to javascript I have been working on a to-do app for the last couple of days, for a coding Bootcamp project and I have updated my coding format so that it is easier to read than what I had before but now the edit and delete functions are not working.
I set up the id and elements for the tasks.
const createTask = () => {
const id = createId()
const task = elements.input.value;
const date = elements.cal.value;
if(!task && !date) return alert("Please fill in task and select date");
if(!task) return alert("Please fill in task");
if(!date) return alert("Please select date");
const tasks = document.createElement("div");
tasks.innerHTML = `
<button class = "sort" data-id="${id}">Sort</button>
<div class="task" date-id = "${id}">
<div class="content">
<input type ="checkbox" class="tick">
<input type ="text" class = text id = "text" data-id="" readonly>${task}
<label class = "due-date" for ="text">${date}</label>
<input type ="date" class = date id = "date">
</div>
<div class = "actions">
<button class="edit" data-id="${id}">Edit</button>
<button class="delete" data-id="${id}">Delet</button>
</div>
</div>
`
elements.list.appendChild(tasks)
return tasks
}
I set up the event listener for the submit, edit and delete. The add list button works fine but the edit and delete button are not working.
elements.list.addEventListener('click',event => {
const {target} = event;
const {id} = target.dataset
const task = id ? document.querySelector('[data-id="${id}"]'): null
const type = {
edit: event.target.classList.contains('edit'),
delete: event.target.classList.contains('delete'),
}
const isFromSaveLabel = target.innerText.toLowerCase() === 'save'
if(tasks && type.edit && isFromSaveLabel){
const text = task.querySelector('text')
target.innerText = 'Edit'
text.addAttribute('readonly')
return
}
if(tasks && type.edit){
const text = task.querySelector('text')
target.innerText = 'Save'
text.removeAttribute('readonly')
text.focus()
return
}
if(tasks && type.delete){
return
}
});
const submitHandler = (event) =>{
event.preventDefault();
createTask();
}
elements.form.addEventListener("submit", submitHandler);
Is it possible for someone to help me to have the following implemented in my code that does the following:
Sort the list alphabetically
can edit the calendar as well when you edit the list you want to change
save the user list using local storage.
It is just those 3 things that need to be added. I code almost every single day for hours and javascript is a bit challenging for me and I do struggle sometimes and this project is due on Friday.
Related
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 build todo list and I like to put on button(.cancel-task) action which remove exactly item which connected with that button, but when I try to put addEventListener I meet error like "its not a function". Please explain me how to make it with using attribute id which I add before for tasks and also how to remove this item from local storage. Thank you, for your attention.
const taskList = document.querySelector(".todo_tasks-wrapper");
const formTodo = document.querySelector(".control");
const inputTask = document.querySelector(".todo_input");
const btnDeleteTask = document.querySelectorAll(".cancel-task");
const taskKeeper = [];
let taskIdCounter = 0;
const data = JSON.parse(localStorage.getItem("tasks"));
const updateHtml = (taskObj) => {
const newLi = document.createElement("li");
newLi.innerHTML = `<li id="${taskObj.id}" class="item-task">
<span>${taskObj.task}</span>
<button class="cancel-task">
<img src="assets/todo-cancel.png" alt="Cancel">
</button>
</li>`;
taskList.append(newLi);
}
const newTask = (info) => {
taskIdCounter += 1;
const taskObj = {
task: info,
id: taskIdCounter,
};
taskKeeper.push(taskObj);
localStorage.setItem("tasks", JSON.stringify(taskKeeper));
updateHtml(taskObj);
};
formTodo.addEventListener("submit", event => {
event.preventDefault();
const info = inputTask.value.trim();
if(info.length !== 0) {
newTask(info);
inputTask.value = "";
inputTask.focus();
}
});
if(data !== null) {
for(let item of data) {
updateHtml(item);
}
}
<div class="todo_wrapper">
<ul class="todo_tasks-wrapper">
</ul>
<form class="control" action="">
<label class="todo_label-form" for="task">
<input class="todo_input" id="task" type="text" placeholder="Enter new task" maxlength="30">
<input class="todo_submit" type="submit" value="+">
</label>
</form>
</div>
You can use a onclick listener on the todo_tasks-wrapper element and check every element inside the event path to match the criterias.
Example:
todoTaskWrapper.addEventListener("click", (event) => {
for (let el of event.composedPath()) {
// window and document have no matches function, but they are included in the path
if (el.matches && el.matches("button.cancel-task")) {
console.log(el, "is the button clicked")
console.log(el.parentNode, "is the li element");
// remove it
el.parentNode.remove();
}
}
});
MDN: Event.composedPath()
MDN: Element.matches()
I am trying to have the complete button disabled when the edit button is pressed.
Here is the render list function
function renderList() {
// This resets the list innerHTML to the new list
el.list.innerHTML = taskList.map(function (data, i) {
return `<div class="task">
<div class="task-content">
<div class="task-set" data-id="${data.id}">
<input class="new-task-created" value="${
data.taskNew
}" readonly style="${data.textDecoration ? "text-decoration: line-through" : ""}"></input>
<input class="due-date" type="date" value="${
data.taskDate
}" readonly></input>
<input class="due-time" type="time" value="${
data.taskTime
}" readonly></input>
</div>
<div class="action-buttons">
<button onclick="editItem(event, ${i})" class="edit" data-id="${data.id}">Edit</button>
<button onclick="deleteItem(event, ${i})" class="delete" data-id="${data.id}">Delete</button>
<button onclick="completeItem(event, ${i})" class="complete" data-id="${data.id}">Complete</button>
</div>`
});
disable()
el.input.value = "";
}
This is my attempt trying to set the attribute to disable to the complete button when the edit button is being pressed.
function disable(){
let selectEdit = document.querySelector(".edit")
let selectComplete = document.querySelector(".complete")
if(selectEdit){
selectComplete.setAttribute("disabled", "true")
}
else{
selectComplete.removeAttribute("disabled")
}
// render list again because you've added a new entry
renderList();
}
Am I doing the set Attribute wrong?
Just an update to the code: The edit button is not working. Below is the complete function. I am not sure if this is causing a conflict with the disable function
//function that that edits tasks with date and time.
function editItem(event, i) {
const editEl = event.target.closest(".task");
let taskUpdate = editEl.querySelector(".new-task-created");
let dateUpdate = editEl.querySelector(".due-date");
let timeUpdate = editEl.querySelector(".due-time");
let editbtn = editEl.querySelector(".edit");
if (editbtn.innerHTML.toLowerCase() == "edit") {
taskUpdate.removeAttribute("readonly");
dateUpdate.removeAttribute("readonly");
timeUpdate.removeAttribute("readonly");
taskUpdate.focus();
editbtn.innerHTML = "Save";
} else {
taskUpdate.setAttribute("readonly", "readonly");
dateUpdate.setAttribute("readonly", "readonly");
timeUpdate.setAttribute("readonly", "readonly");
editbtn.innerHTML = "Edit";
taskList[i] = {
id: taskList[i].id,
taskNew: taskUpdate.value,
taskDate: dateUpdate.value,
taskTime: timeUpdate.value,
};
// store the list on localstorage because data changed
storeList();
// render list again because you've added a new entry
renderList();
}
}
I managed to find a solution.
I got the HTML element let selectComplete = document.querySelector(".complete") and added it to the editItem function and set the attribute of selectComplete to selectComplete.setAttribute("disabled", "")
The editItem function now looks like this:
//function that that edits tasks with date and time.
function editItem(event, i) {
const editEl = event.target.closest(".task");
let taskUpdate = editEl.querySelector(".new-task-created");
let dateUpdate = editEl.querySelector(".due-date");
let timeUpdate = editEl.querySelector(".due-time");
let editbtn = editEl.querySelector(".edit");
let selectComplete = document.querySelector(".complete")
if (editbtn.innerHTML.toLowerCase() == "edit") {
taskUpdate.removeAttribute("readonly");
dateUpdate.removeAttribute("readonly");
timeUpdate.removeAttribute("readonly");
taskUpdate.focus();
//Set the disable for the complete button.
selectComplete.setAttribute("disabled", "");
editbtn.innerHTML = "Save";
} else {
taskUpdate.setAttribute("readonly", "readonly");
dateUpdate.setAttribute("readonly", "readonly");
timeUpdate.setAttribute("readonly", "readonly");
selectComplete.removeAttribute('disabled');
editbtn.innerHTML = "Edit";
taskList[i] = {
id: taskList[i].id,
taskNew: taskUpdate.value,
taskDate: dateUpdate.value,
taskTime: timeUpdate.value,
};
// store the list on localstorage because data changed
storeList();
// render list again because you've added a new entry
renderList();
}
}
I have a problem in Javascript.I am adding new list items to the 'ul' elements and this list is empty at first and I do not want to add same values twice. When I write the if statement I get the exception because my list is empty so the result return null.
How can I fix this this problem?
Thank you in advance...
Html Codes
<input type="text" id="the-filter" placeholder="Search For..." />
<div class="list-container">
<ul id="myList"></ul>
<button id="button">Click</button>
Javascript Codes
let newlist = document.querySelector("#myList");
const li = document.getElementsByClassName('list-group-item');
const button = document.getElementById("button");
const button.addEventListener('click' , listName);
const input = document.getElementById("the-filter");
function listName()
const inputVal = input.value;
for (i = 0; i < li.length; i++) {
if ((li[i].innerHTML.toLocaleLowerCase().includes(inputVal) && inputVal!="") ||
(li[i].innerHTML.toUpperCase().includes(inputVal) && inputVal!="")) {
let newItem = document.createElement("li");
li[i].classList.add("list-group-item");
let textnode = document.createTextNode(li[i].innerHTML.toLocaleLowerCase());
newItem.appendChild(textnode);
if((newlist.children[0].innerHTML.toLocaleLowerCase().includes(inputVal))){
newlist.insertBefore(newItem, newlist.childNodes[0]);
}
}
}
}
If I understood the task correct, you need to add items to the list by button click.
If same item exists (case insensitive), then nothing happens.
const list = document.querySelector("#myList");
const button = document.getElementById("button");
button.addEventListener("click", listName);
const input = document.getElementById("the-filter");
function listName() {
const inputVal = input.value;
const [...lis] = document.getElementsByClassName("list-group-item");
const same = lis.find((el) => el.textContent.toLowerCase() === inputVal.toLowerCase());
if (same) {
return;
}
let newItem = document.createElement("li");
newItem.classList.add("list-group-item");
newItem.textContent = inputVal;
list.appendChild(newItem)
}
<input type="text" id="the-filter" placeholder="Search For..." />
<div class="list-container">
<ul id="myList"></ul>
<button id="button">Click</button>
</div>
You're on the right track with event listeners and element creation, but your original code didn't quite seem to match your stated goal.
Here's a solution you might find useful, with some explanatory comments:
// Identifies some DOM elements
const
input = document.getElementById("my-input"),
newList = document.getElementById("my-list"),
items = document.getElementsByClassName('list-group-item'),
button = document.getElementById("my-button");
// Focuses input, and calls addItem on button-click
input.focus();
button.addEventListener('click', addItem);
// Defines the listener function
function addItem(){
// Trims whitespace and sets string to lowerCase
const inputTrimmedLower = input.value.trim().toLocaleLowerCase();
// Clears and refocuses input
input.value = "";
input.focus();
// Ignores empty input
if (!inputTrimmedLower) { return; }
// Ignores value if a list item matches it
for (const li of items) {
const liTrimmedLower = li.textContent.trim().toLocaleLowerCase();
if (liTrimmedLower === inputTrimmedLower) {
console.log(`${inputTrimmedLower} is already listed`);
return;
}
}
// If we got this far, we want to add the new item
let newItem = document.createElement("li");
newItem.classList.add("list-group-item");
newItem.append(inputTrimmedLower); // Keeps lowerCase, as your original code
newList.prepend(newItem); // More modern method than `insertBefore()`
}
<input id="my-input" />
<ul id="my-list"></ul>
<button id="my-button">Click</button>
Im trying to console out a radio button with JS in order to see the value of the checked button. the Js seems to be without syntax error, but it returns undefined:
this is the HTML:
const firstName = document.querySelector('#FirstName');
const lastName = document.querySelector('#LastName');
const email = document.querySelector('#email');
const comments = document.querySelector('#comments');
let meeting1 = document.querySelector('#meetingtype1');
let meeting2 = document.querySelector('#meetingtype2');
let meeting3 = document.querySelector('#meetingtype3');
let meeting4 = document.querySelector('#meetingtype4');
let meeting;
if (meeting1.checked) {
meeting = meeting1.value;
console.log(meeting = "1");
} else if (meeting2.checked) {
meeting = meeting2.value;
console.log(meeting = "2")
} else if (meeting3.checked) {
meeting = meeting3.value;
console.log(meeting = "3")
} else if (meeting4.checked) {
meeting = meeting4.value;
console.log(meeting = "4")
}
const submitform = document.querySelector('#submitform');
submitform.addEventListener('click', function() {
console.log(` Name: ${firstName.value}, Last Name: ${lastName.value}, Email: ${email.value}, Comment: ${comments.value} Type of meeting: ${meeting}`);
});
<fieldset>
<legend>Would you like to meet for?</legend>
<label><input type="radio" id="meetingtype1" name=meetingtype value="coffee" > A coffee</label>
<label><input type="radio" id="meetingtype2" name=meetingtype value="zoom"> A zoom meeting</label>
<label><input type="radio" id="meetingtype3" name=meetingtype value="drive"> A drive to Eilat</label>
<label><input type="radio" id="meetingtype4" name=meetingtype value="chef"> A chef meal</label>
<button id="submitform" type="submit">Submit</button>
thank you very much!
Since you want to check the value/log it onto your console when you are going to click onto your button, make sure to use your if-else-statement inside of the EventListener and not outside of the function. If you write the if-else-statement in your way, it will be executed when the page loads the first time.
To print out your current value of the selected meeting change your JavaScript Code to this. I modified your provided code.
let meeting1 = document.querySelector('#meetingtype1');
let meeting2 = document.querySelector('#meetingtype2');
let meeting3 = document.querySelector('#meetingtype3');
let meeting4 = document.querySelector('#meetingtype4');
let meeting;
const submitform = document.querySelector('#submitform');
submitform.addEventListener('click', function () {
if (meeting1.checked){
meeting = meeting1.value;
} else if (meeting2.checked){
meeting = meeting2.value;
} else if (meeting3.checked){
meeting = meeting3.value;
} else if (meeting4.checked){
meeting = meeting4.value;
}
console.log(`Type of meeting: ${meeting}`);
});