I'm trying to build a simple todo list. I would like to add a (x) to each item in the list. The list has two existing items, and the rest will be added from user input.
My current code can only add (x) to existing items. I followed the following tutorial, but i think the way it adds (x) to both existing items and new input items are redundant. (note it basically uses "var span = document.createElement("SPAN"); ..." twice.
Is there a way that I can append the (x) in the end to all li items in the document?
// Create a "close" button and append it to each list item
var allListItems = document.getElementsByTagName("li");
function appendClose(x){
var close = document.createElement("span");
var text = document.createTextNode("(\u00D7)");
close.appendChild(text);
return x.appendChild(close);
}
// Turn object into array.
const peopleArray = Object.keys(allListItems).map(i => allListItems[i]);
console.log(peopleArray);
peopleArray.map(appendClose);
// Create new list item after button click.
function createNewElement(){
var li = document.createElement("li"); // create <li>
var v_userInput = document.getElementById("myInput");
var content = document.createTextNode(v_userInput.value);
li.appendChild(content);
document.getElementById("myUL").appendChild(li);
document.getElementById("myInput").value = ""; //fresh the input box;
};
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Work to-do</title>
</head>
<body>
<h1> Work to-do </h1>
<div id="myDiv">
<input id="myInput" type="text" placeholder="New item..." maxlength="27">
<button id="enter" onclick="createNewElement()">Add</button>
</div>
<ul id="myUL">
<li>Gym</li>
<li>Food</li>
</ul>
</body>
<script type="text/javascript" src="7_todo.js"></script>
</html>
You just have to write one more line inside createNewElement() to do that:
appendClose(li);
Further, you should also prevent empty values being appended to todo-list by checking the length of input value. I've added an example of that.
// Create a "close" button and append it to each list item
var allListItems = document.getElementsByTagName("li");
function appendClose(x){
var close = document.createElement("span");
var text = document.createTextNode("(\u00D7)");
close.appendChild(text);
return x.appendChild(close);
}
// Turn object into array.
const peopleArray = Object.keys(allListItems).map(i => allListItems[i]);
// console.log(peopleArray);
peopleArray.map(appendClose);
// Create new list item after button click.
function createNewElement(){
var li = document.createElement("li"); // create <li>
var v_userInput = document.getElementById("myInput");
// Prevents empty task in todo list
if(v_userInput.value.length === 0) {
alert('Enter something!');
return ;
}
var content = document.createTextNode(v_userInput.value);
li.appendChild(content);
appendClose(li); // Edited here
document.getElementById("myUL").appendChild(li);
document.getElementById("myInput").value = ""; //fresh the input box;
};
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Work to-do</title>
</head>
<body>
<h1> Work to-do </h1>
<div id="myDiv">
<input id="myInput" type="text" placeholder="New item..." maxlength="27">
<button id="enter" onclick="createNewElement()">Add</button>
</div>
<ul id="myUL">
<li>Gym</li>
<li>Food</li>
</ul>
</body>
<script type="text/javascript" src="7_todo.js"></script>
</html>
Related
So been trying to learn more javascript, by doing small projects that are simple but are starting stuff. One of the projects is a to-do app which for some people is really simple, but for me as a starter it's quite complex.
Now here is the thing, I had it working for the most part, I can add stuff, and one thing only HALF works, I wrote a bit that adds a X button to a li element. Now it works when I put the li element in the HTML page itself, but when it's added through javascript, it doesn't.
There is no error, it was working before but for some reason it.. broke.
<!DOCTYPE html>
<head>
<title>To Do App!</title>
<link rel="stylesheet" type="text/css" href="CSS/stylesheet.css">
</head>
<body>
<div id="h1Div">
<h1> To-do app! </h1>
<input type="text" id="inputForList">
<input type="button" id="btnInput" value="Add me!" onclick="btnFunction()">
</div>
<ul id="ulSection">
<li>Test 1</li>
<li>Test 2</li>
</ul>
<script src="Scripts/javascript.js"></script>
</body>
This is the HTML page, super simple.
//Adds li element with input from a textbox
function btnFunction(){
var cLi = document.createElement("li");
var inpList = document.getElementById("inputForList").value;
var txtNode = document.createTextNode(inpList);
cLi.appendChild(txtNode);
//Check to see if anything is filled in, otherwise send message. And 'appends' it to the list item
if(inpList === ''){
alert("Voeg wat toe!");
} else {
document.getElementById("ulSection").appendChild(cLi);
}
// Reset value of Textbox to ""
document.getElementById("inputForList").value = "";
}
//Sets a 'x' on every element.
var ulList = document.getElementsByTagName("li");
var i;
for(i = 0; i < ulList.length; i++){
var span = document.createElement("span");
var xBtn = document.createTextNode("\u00D7");
span.className = "Done";
span.appendChild(xBtn);
ulList[i].appendChild(span);
}
And this is the Javascript.
As stated, it worked before. But for some reason, now the bottom section, the X button (\u00D7) part, it sn't working on the 'new stuff' that I add through the text input..
Your code is good, you just need to do the same thing you did in
var ulList = document.getElementsByTagName("li");
var i;
for (i = 0; i < ulList.length; i++) {
var span = document.createElement("span");
var xBtn = document.createTextNode("\u00D7");
span.className = "Done";
span.appendChild(xBtn);
ulList[i].appendChild(span);
}
in btnFunction() (with the exception of the for loop, which isn't needed in the function, as only one element is added at a time). The reason for this is your code only runs when the page is loaded, or when it is specifically told to run (in your case, on a button click). if you just create an element the js doesn't know to update it with an x, you have to tell it to do so.
//Adds li element with input from a textbox
function btnFunction() {
var cLi = document.createElement("li");
var inpList = document.getElementById("inputForList").value;
var txtNode = document.createTextNode(inpList);
cLi.appendChild(txtNode);
//Check to see if anything is filled in, otherwise send message. And 'appends' it to the list item
if (inpList === '') {
alert("Voeg wat toe!");
} else {
document.getElementById("ulSection").appendChild(cLi);
var ulList = document.getElementsByTagName("li");
var span = document.createElement("span");
var xBtn = document.createTextNode("\u00D7");
span.className = "Done";
span.appendChild(xBtn);
ulList[ulList.length-1].appendChild(span);
}
// Reset value of Textbox to ""
document.getElementById("inputForList").value = "";
}
//Sets a 'x' on every element.
var ulList = document.getElementsByTagName("li");
var i;
for (i = 0; i < ulList.length; i++) {
var span = document.createElement("span");
var xBtn = document.createTextNode("\u00D7");
span.className = "Done";
span.appendChild(xBtn);
ulList[i].appendChild(span);
}
<!DOCTYPE html>
<head>
<title>To Do App!</title>
<link rel="stylesheet" type="text/css" href="CSS/stylesheet.css">
</head>
<body>
<div id="h1Div">
<h1> To-do app! </h1>
<input type="text" id="inputForList">
<input type="button" id="btnInput" value="Add me!" onclick="btnFunction()">
</div>
<ul id="ulSection">
<li>Test 1</li>
<li>Test 2</li>
</ul>
<script src="Scripts/javascript.js"></script>
</body>
I'm creating a to-do list for class:
Lab 4: Todo List Let's make a simple todo-list which supports the
following operations: add an item to the list remove an item from the
list mark an item as completed Removed items should disappear
entirely. Completed items should appear at the bottom (or in a
separate list) with a line through them.
I'm unable to remove multiple li from my ul. I get an error after removing the first.
lab-04.js:16 Uncaught DOMException: Failed to execute 'removeChild' on
'Node': The node to be removed is not a child of this node. at
HTMLButtonElement.removeBtn.onclick
(http://127.0.0.1:5500/js/lab-04/lab-04.js:16:18)
Oddly, enough the buttons are removed without much fuss.
The code (js):
let manipulateDom = () => {
let container = document.getElementsByClassName('container')
let toDoList = document.getElementById('to-do')
let removeBtn = document.createElement('button')
content = document.getElementById('userInput').value
listItem = document.createElement('li')
listItem.className = 'list-item'
listItem.textContent = (content)
removeBtn.appendChild(document.createTextNode('remove'))
removeBtn.onclick = function() {
toDoList.removeChild(removeBtn)
toDoList.removeChild(listItem)
}
toDoList.appendChild(listItem)
toDoList.appendChild(removeBtn)
}
(html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>lab-04</title>
<script src='/js/lab-04/lab-04.js'></script>
</head>
<body>
<h4>To Do List</h4>
<input type='text' id='userInput' placeholder="item to add">
<input type="submit" onclick="manipulateDom()">
<ul id='to-do'>
</ul>
<ul id='done'>
</ul>
</body>
</html>
Any help is greatly appreciated, ready to pull my hair out
You are putting your listItem in the window scope, and what removeBtn.onclick does is removing the listItem in the window scope, that's why the remove button only works once and only works on the last element created.
Declare listItem in the block scope and it should be working again
let manipulateDom = () => {
let container = document.getElementsByClassName('container');
let toDoList = document.getElementById('to-do');
let removeBtn = document.createElement('button');
let content = document.getElementById('userInput').value;
let listItem = document.createElement('li');
listItem.className = 'list-item';
listItem.textContent = (content);
removeBtn.appendChild(document.createTextNode('remove'))
removeBtn.onclick = function() {
toDoList.removeChild(removeBtn);
toDoList.removeChild(listItem);
};
toDoList.appendChild(listItem);
toDoList.appendChild(removeBtn);
}
<h4>To Do List</h4>
<input type='text' id='userInput' placeholder="item to add">
<input type="submit" onclick="manipulateDom()">
<ul id='to-do'>
</ul>
<ul id='done'>
</ul>
I don't have coding experience, am in the process of learning.
I'm very very confuse as to what/how I should proceed setItem to localStorage and getItem from localStorage . So when webpage refresh, saved todo items would still be there.
I seen quite a few youtube videos and blog posts, but cant quite seem to understand .
I know I need to
-push input value into an array
-save that to localStorage with JSON.stringify
-when page refresh, check if there's data in localStorage
-if true, getItem from localStorage with JSON.parse
-if false, do nothing.
Can someone please explain like I'm five.
const toDoForm = document.querySelector('#todo-form');
const toDoInput = document.querySelector('#todo');
const ulList = document.querySelector('#ulList');
let dataArray = [];
toDoForm.addEventListener('submit', function (e) {
//stop submit event from refreshing
e.preventDefault();
//when submit -> create a element <li> link it with variable newLi
//Fill new <li>innerText</li> with toDoInput's value
const newLi = document.createElement('li');
newLi.innerText = toDoInput.value;
//when submit -> create a element <button></button> link it with variable btn
//<button>x</button>
//append <button>x</button> to newLi <li><button>x</button></li>
const btn = document.createElement('button');
btn.innerText = 'x';
newLi.appendChild(btn);
//add newLi <li><button>x</button></li> to ulList<ul></ul>
ulList.appendChild(newLi);
//push input into an empty array called dataArray
dataArray.push(toDoInput.value);
localStorage.setItem('localData', JSON.stringify(dataArray));
//when submit -> after all the above is done, we will set the input field to empty string
toDoInput.value = '';
});
ulList.addEventListener('click', function (e) {
if (e.target.tagName === 'BUTTON') {
e.target.parentElement.remove();
} else if (e.target.tagName === 'LI') {
e.target.classList.toggle('line');
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>TO DO LIST</h1>
<ul id="ulList">
</ul>
<form action="" id="todo-form">
<label for="todo">Write down things to do</label>
<input type="text" id="todo" name="todo">
<input type="submit">
</form>
<script src="app.js"></script>
</body>
</html>
You can extract the code to add a TODO item to a function and then call that function for each element in the array stored in localStorage if it is found.
let dataArray = localStorage.getItem('localData') ? JSON.parse(localStorage.getItem('localData')): [];
dataArray.forEach(addTodo);
function addTodo(todo){
const newLi = document.createElement('li');
newLi.innerText = todo;
//when submit -> create a element <button></button> link it with variable btn
//<button>x</button>
//append <button>x</button> to newLi <li><button>x</button></li>
const btn = document.createElement('button');
btn.innerText = 'x';
newLi.appendChild(btn);
//add newLi <li><button>x</button></li> to ulList<ul></ul>
ulList.appendChild(newLi);
}
toDoForm.addEventListener('submit', function (e) {
//stop submit event from refreshing
e.preventDefault();
addTodo(toDoInput.value);
dataArray.push(toDoInput.value);
localStorage.setItem('localData', JSON.stringify(dataArray));
//when submit -> after all the above is done, we will set the input field to empty string
toDoInput.value = '';
});
Demo
Firstly I know I can make things a lot easier by creating the ul in HTML. I'm not supposed to be doing that.
My HTML:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body id="body">
<form id="form" >
<input id="userInput" placeholder="Enter your list item here">
<button type="button" onclick="inputFunction()">Add</button>
</form>
<script src="A4.js"></script>
</body>
</html>
My Javascript so far:
// Creating Array
var listData = ["Crab","Lobster","Scallops"];
// Creating initial List
function listFunction(){
var ul = document.createElement("ul");
ul.id = 'ulId';
document.getElementById('body').appendChild(ul);
listData.forEach(liFunction);
function liFunction(element){
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML+=element;
}
}
listFunction();
// Adding user input to the list
function inputFunction() {
var input = document.getElementById("userInput").value;
listData.push(input);
var newLi = document.createElement("li");
document.getElementById('ulId').appendChild(newLi);
newLi.innerHTML=input;
}
var liImg = document.getElementsByTagName('li');
for (var i = 0; i < liImg.length; i++) {
liImg[i].addEventListener('mouseover', handlerFunction, false);
}
function handlerFunction(e) {
var img = document.createElement("img");
img.setAttribute("src","https://cdn1.iconfinder.com/data/icons/nuove/128x128/actions/fileclose.png");
img.setAttribute("height","10");
img.setAttribute("width", "10");
document.getElementsByTagName('li').innerHTML += "img";
}
So what I'm supposed to be doing is first create a list using the listData array, and displaying it on the page. Then I take the user input and add it to the list. This part is working fine
The part I am stuck on is having to create/display an image next to each list item when it is mouseover'ed. Then having to delete that specific list item if the image is clicked. I've created the eventListener, but the img part doesn't seem to be working.
The problem is when you're appending the image to the li element.
Solution:
e.target.appendChild(img);
// Creating Array
var listData = ["Crab", "Lobster", "Scallops"];
// Creating initial List
function listFunction() {
var ul = document.createElement("ul");
ul.id = 'ulId';
document.getElementById('body').appendChild(ul);
listData.forEach(liFunction);
function liFunction(element) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML += element;
}
}
listFunction();
// Adding user input to the list
function inputFunction() {
var input = document.getElementById("userInput").value;
listData.push(input);
var newLi = document.createElement("li");
document.getElementById('ulId').appendChild(newLi);
newLi.innerHTML = input;
}
var liImg = document.getElementsByTagName('li');
for (var i = 0; i < liImg.length; i++) {
liImg[i].addEventListener('mouseover', handlerFunction);
}
function handlerFunction(e) {
var img = document.createElement("img");
img.setAttribute("src", "https://cdn1.iconfinder.com/data/icons/nuove/128x128/actions/fileclose.png");
img.setAttribute("height", "10");
img.setAttribute("width", "10");
e.target.appendChild(img);
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body id="body">
<form id="form">
<input id="userInput" placeholder="Enter your list item here">
<button type="button" onclick="inputFunction()">Add</button>
</form>
<script src="A4.js"></script>
</body>
</html>
Hope this helps!
img is not string, it is a variable, so remove the surrounding double quotes from that. Since img is a node element, instead of using innerHTML you should use appendChild(). You also should use the e.target to refer the specific li element:
Change:
document.getElementsByTagName('li').innerHTML += "img";
To
e.target.appendChild(img);
I will suggest you to use mouseenter instead of mousemove. I think you need to attach the mouseleave event as well. You also have to attach the events to the newly created li elements.
Try the following way:
// Creating Array
var listData = ["Crab","Lobster","Scallops"];
// Creating initial List
function listFunction(){
var ul = document.createElement("ul");
ul.id = 'ulId';
document.getElementById('body').appendChild(ul);
listData.forEach(liFunction);
function liFunction(element){
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML+=element;
}
}
listFunction();
// Adding user input to the list
function inputFunction() {
var input = document.getElementById("userInput").value;
listData.push(input);
var newLi = document.createElement("li");
newLi.addEventListener('mouseenter', handlerFunction, false);
newLi.addEventListener('mouseleave', removeImage, false);
document.getElementById('ulId').appendChild(newLi);
newLi.insertAdjacentHTML('beforeend', input);
}
var liImg = document.getElementsByTagName('li');
for (let i = 0; i < liImg.length; i++) {
liImg[i].addEventListener('mouseenter', handlerFunction, false);
liImg[i].addEventListener('mouseleave', removeImage, false);
}
function handlerFunction(e) {
var img = document.createElement("img");
img.setAttribute("src","https://cdn1.iconfinder.com/data/icons/nuove/128x128/actions/fileclose.png");
img.setAttribute("height","30");
img.setAttribute("width", "30");
img.addEventListener('click', function(){
this.closest('li').remove();
});
e.target.appendChild(img);
}
function removeImage(e){
e.target.querySelector('img').remove();
}
<body id="body">
<form id="form" >
<input id="userInput" placeholder="Enter your list item here">
<button type="button" onclick="inputFunction()">Add</button>
</form>
<script src="A4.js"></script>
</body>
I am new in javascript and in this moment I am trying to use "Basic DOM and JS". I am doing a dropdown menu, what gets his elements from an array. There is an input field, where you can add new items into the array.I also made a button to push and save the item into array and make the dropdown automatically with DOM.
My problem if you push the button, it makes always a new dropdown menu. Otherwise the array works good, but I need just one dropdown menu with the items of array. I think this problem comes out at listing with ul li too. Here is my whole code and thanks for helping
<!DOCTYPE html>
<html>
<head>
<style>
</style>
<meta charset="utf-8">
<script>
var select = new Array;
function array(){
var input = document.getElementById("input");
var value = input.value;
select.push(value);
var menu = document.createElement("select");
document.body.appendChild(menu);
for(var i = 0; i<select.length; i++){
var option = document.createElement("option");
var text = document.createTextNode(select[i]);
option.appendChild(text);
menu.appendChild(option);
}
}
</script>
</head>
<body>
<input id="input" type="text">
<input onclick="array()" type="button" value="Add">
</body>
</html>
You are creating the select tag every time array() is invoked. So create select tag once and rest of the time create option tag when array() is invoked. Here is your solution.
<!DOCTYPE html>
<html>
<head>
<style>
</style>
<meta charset="utf-8">
<script>
var select = new Array;
var selectIsCreated = false;
var menu;
function array(){
var input = document.getElementById("input");
var value = input.value;
select.push(value);
if(!selectIsCreated){
menu = document.createElement("select");
document.body.appendChild(menu);
selectIsCreated = true;
}
var option = document.createElement("option");
var text = document.createTextNode(select[select.length-1]);
option.appendChild(text);
menu.appendChild(option);
}
</script>
</head>
<body>
<input id="input" type="text">
<input onclick="array()" type="button" value="Add">
</body>
</html>
So Suman already answered your question, but in terms of simplifying the code or the approach, I think you could take a different approach by removing the use of the "select" array entirely. The array isn't necessary to add in the value to the select list, as you can get everything you need from the input element, so you just need to work on adding the option to the actual select DOM element.
Here is the desired functionality re-factored a bit with this in mind.
<!DOCTYPE html>
<html>
<head>
<style>
</style>
<meta charset="utf-8">
<script>
function createSelect() {
select = document.createElement('select');
select.id = 'select';
document.body.appendChild(select);
return document.getElementById('select');
}
function addOption(){
var input = document.getElementById("input");
var value = input.value;
// This will attempt to grab the 'select' element, but if it finds
// that it doesn't exist (i.e. getElementById returns a "falsy" value)
// then it will return the value of the createSelect function.
// This could also be done with more explicit "if" statements
var menu = document.getElementById('select') || createSelect();
// The same effect could be achieved by running this code:
/*
var menu = document.getElementById('select');
// If the select element hasn't been created/added to the page yet,
// then the above call to getElementById will return a "falsy" value,
// i.e. a value that isn't a strict boolean type but JS will treat it
// as "false".
if (!menu) {
menu = createSelect();
}
*/
var option = document.createElement("option");
var text = document.createTextNode(value);
option.appendChild(text);
menu.appendChild(option);
}
</script>
</head>
<body>
<input id="input" type="text">
<!--
I've renamed the array() function since we don't even
have an array anymore
-->
<input onclick="addOption()" type="button" value="Add">
</body>
</html>
You can see this in action on this jsFiddle