How to delete an item on click from dynamically generated content javascript - javascript

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>

Related

ToDo List. Delete task button

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()

how to refresh only a form or fieldset not a page

in my SPRING project, I have an index.html file that has two forms. When you write a name in the first one and click submit the name is transferred to another one. The other form is connected with DB and displays it in a fieldset.
I have two buttons:
1)ADD to DB - when I ADD an item I can see it right away
2)DELETE an item from DB by ID - it works and deletes from DB, but the view isn't refreshed/reloaded. I need to refresh the whole page to see the results of DELETED item.
When I refresh the page it is going back to the first form with the name...
I wonder how to solve it.
I know something must be written inside the DELETE function.
PLEASE HELP.
<!DOCTYPE html>
<html lang="en" xmlns:https="http://www.w3.org/1999/xhtml" xmlns:http="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>SHOPPING LIST</title>
<link rel="stylesheet" href="https://unpkg.com/purecss#1.0.0/build/pure-min.css"
integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous">
</head>
<body>
<main style="width: 40%; margin: 0 auto">
<div id="welcome" style="text-align: center">
<h1>Introduce yourself</h1>
</div>
<form id="welcomeForm" class="pure-form pure-g pure-form-aligned">
<input class="pure-input-rounded pure-u-1" name="name" placeholder="name" id="text_name">
<button id="welcomeFormBtn" class="pure-button pure-button-primary pure-u-1">Submit</button>
</form>
<form id="AddForm" class="pure-form" style="text-align: center; display: none">
<fieldset>
<input id="name" class="pure-input-rounded pure-input-2-3" style="width: available" placeholder="name">
<input id="amount" class="pure-input-rounded pure-input-2-3" style="width: available" placeholder="amount">
<input id="uom" class="pure-input-rounded pure-input-2-3" style="width: available" placeholder="unit of measure">
<input id="idToDel" type="number" class="pure-input-rounded pure-input-2-3" style="width: available" placeholder="Please provide an id to delete">
</fieldset>
<fieldset>
<button id="addProduct" class="pure-button pure-button-primary">POST</button>
<button id="delProduct" class="pure-button pure-button-primary">DELETE</button>
<br>
<button id="print-btn" style="width: 50px; height: 50px; border-radius: 50%"><img style="width: 40px; height: 40px" src="https://cdn-icons-png.flaticon.com/512/3233/3233446.png" alt="PRINT"></button>
</fieldset>
<fieldset id="allProducts" >
</fieldset>
</form >
</main>
<script>
const API_URL = 'http://localhost:8080';
const API_URL_ADD = `${API_URL}/api`;
const API_URL_ALL = `${API_URL_ADD}/list`;
const pName = document.getElementById('name');
const pUom = document.getElementById('uom');
const pAmount = document.getElementById('amount');
AddFunction();
fetch(API_URL_ALL)
.then(processOkResponse)
.then(list => list.forEach(createNewProduct))
document.getElementById('addProduct').addEventListener('click', (event) => {
event.preventDefault();
fetch(API_URL_ALL, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: pName.value, type : pUom.value, amount: pAmount.value })
})
.then(processOkResponse)
.then(createNewProduct)
.then(() => pName.value = '')
.then(() => pAmount.value = '')
.then(() => pUom.value = '')
.catch(console.warn);
});
function createNewProduct(product) {
const label = document.createElement('label');
const l1 = document.createElement('label');
const l2 = document.createElement('label');
const l3 = document.createElement('label');
const l4 = document.createElement('label');
label.classList.add('label');
l1.appendChild(document.createTextNode(` ID:${product.id}. `));
l2.appendChild(document.createTextNode(` ${product.name} `));
l3.appendChild(document.createTextNode(` ${product.amount} `));
l4.appendChild(document.createTextNode(` ${product.type} `));
label.appendChild(l1).appendChild(l2).appendChild(l3).appendChild(l4)
document.getElementById('allProducts').appendChild(label);
label.style.display= 'table';
label.style.paddingLeft='40%';
label.style.wordSpacing='30%';
}
document.getElementById('delProduct').addEventListener('click', (event) => {
event.preventDefault();
removeTodo();
});
function removeTodo() {
const d = document.getElementById('idToDel').value;
fetch(`${API_URL_ALL}/${d}`, { method: 'DELETE' })
.then(processOkResponse)
.catch(console.info)
}
function AddFunction(){
const welcomeForm = document.getElementById('welcomeForm');
document.getElementById('welcomeFormBtn').addEventListener('click', (event) => {
event.preventDefault();
const formObj = {
name: welcomeForm.elements.name.value,
};
fetch(`${API_URL_ADD}?${new URLSearchParams(formObj)}`)
.then(response => response.text())
.then((text) => {
document.getElementById('welcome').innerHTML = `
<h1>${text}</h1>
`;
welcomeForm.remove();
document.getElementById('AddForm').style.display = 'block';
});
});
}
document.getElementById('print-btn').addEventListener('click', (event) => {
event.preventDefault();
const f = document.getElementById("allProducts").innerHTML;
const a = window.open();
a.document.write(document.getElementById('welcome').innerHTML);
a.document.write(f);
a.print();
})
function processOkResponse(response = {}) {
if (response.ok) {
return response.json();
}
throw new Error(`Status not 200 (${response.status})`);
}
</script>
</body>
</html>
just like you've done .then(processOkResponse).then(createNewProduct) for adding a product, you should do the same for deletion as well.
.then(processOkResponse).then(deleteProduct) in your removeToDo function as well.
You should add a specific id to the label you're creating in createNewProduct(product) function like this
function createNewProduct(product) {
const label = document.createElement('label');
label.setAttribute('id', `pid-${product.id}`); // just this line to be added
//.... rest of your code
function deleteProduct(deleteApiResponse) {
// make sure to send id value of the deleted product
const {id} = deleteApiResponse;
const idToDel = `pid-${id}`;
// this does remove from HTML. just sets display: none
document.getElementById(idToDel).style.display = 'none';
// or remove from HTML like this. but for this you need the parentId
// to effectively remove the style(if any) on the id to be delete
//document.getElementById(idToDelParent).innerHTML = '';
}

Add task to tasklist from JS to HTML page

I am trying to input a new task. It will only allow me to add one task. If I input another it just removes the last. How can I save multiple?
HTML Code:
<h2>Future Projects</h2>
<div id="projects">
<div class="project">first</div>
<div class="project">y</div>
<div class="project">last</div>
</div>
<form action="index.html" get>
<label for="message">Meaningful Message:</label>
<br>
<textarea name="message" id="message" rows="1" cols="20">
</textarea>
<br>
<input type="submit" value="submit">
</form>
</div>
JS Code:
const message = words.get('message');
if(message.value !== '') {
let e = document.createElement('div')
e.innerHTML = `${message}`
e.className = 'project'
let parent = document.getElementById('projects')
parent.append(e);
e.preventDefault()
}
Try apppendChild.
const project = document.createElement("div");
project.innerText = "text";
//...
const parent = document.getElementById('projects');
parent.appendChild(project);
I was able to get it !
JS Changes:
let submit = document.getElementById('submit').addEventListener('click', add)
function add(event){
event.preventDefault()
let message = document.getElementById('message').value
let parent = document.getElementById('projects')
parent.innerHTML += `<div class="project">${message}</div>`
}
and
let submit = document.getElementById('submit').addEventListener('click', add)
function add(event){
event.preventDefault()
let message = document.getElementById('message').value
let parent = document.getElementById('projects')
let e = document.createElement('div')
e.innerHTML = `${message}`
e.className = 'project'
parent.appendChild(e);
}

input Tag returning Empty String on using value property

// 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>

Find and compare input value with JSON data

I'm trying to compare user input value with JSON data.
I found some questions similar to this one, but it didn't solve my problem.
This is my code, do you know why it doesn't work.
Javascript
fetch('js/countries.json')
.then(res => res.json())
.then(data => {
function checkCountry() {
let input = document.getElementById("countryInput").value;
let country = data.find(check => check.country === "Norway");
let text;
if (input === data[country]) {
text = "Yes";
} else {
text = "No";
}
document.getElementById("alert").innerHTML = text;
}
document.getElementById("check").addEventListener("click", checkCountry);
console.log(data);
})
JSON
[{"country":"USA","active":true},
{"country":"Spain","active":true},
{"country":"Norway","active":true}]
HTML
<form action="">
<div class="input-container">
<input id="countryInput" type="text" placeholder="Country">
<i class="fas fa-search"></i>
</div>
<button id="check" type="button">CHECK</button>
</form>
This line is not good: if (input === data[country]) {
you have to check with the same mechanism as you have checked for country above...
let inputCountry = data.find(check => check.country === input);
Like this:
const data = [{"country":"USA","active":true},
{"country":"Spain","active":true},
{"country":"Norway","active":true}];
document.getElementById("check").addEventListener("click", checkCountry);
function checkCountry() {
let input = document.getElementById("countryInput").value;
let country = data.find(check => check.country === "Norway");
let inputCountry = data.find(check => check.country === input);
let text;
// You have to check with the country
if (inputCountry && input === inputCountry.country) {
text = "Yes";
} else {
text = "No";
}
console.log(text);
}
<form action="">
<div class="input-container">
<input id="countryInput" type="text" placeholder="Country">
<i class="fas fa-search"></i>
</div>
<button id="check" type="button">CHECK</button>
</form>
You can't use data[country] because data isn't key value pair collection.
It consists of objects.
Try to change resulting json from {'country': 'Spain', 'active': true}, ... to
'Spain': {active: true}, ...
Or call data element via:
if (input === data.find(el => el.country == country)) {
text = "Yes";
} else {
text = "No";
}

Categories