I have a simple script that adds an 'li' element with input text value to the list after clicking a button, but I also want to clear this input after clicking the button. Here is the HTML:
<form class="form">
<input id="newInput" type="text" placeholder="Dodaj pozycję">
<button id="createNew" type="button">Dodaj</button>
</form>
<h2>Moja lista:</h2>
<div class="listBg">
<ul id="list">
</ul>
</div>
<button id="deleteAll" type="button">Wyczyść</button>
And JS:
function addItem(){
var myList = document.getElementById("list");
var newListItem = document.createElement("li");
var itemText = document.getElementById("newInput").value;
var listText = document.createTextNode(itemText);
newListItem.appendChild(listText);
if (itemText === "") {
alert("Pole nie może być puste");
} else {
myList.appendChild(newListItem);
}
};
function clearText(){
var itemText = document.getElementById("newInput").value;
itemText.innerText = "";
};
var addButton = document.getElementById("createNew");
addButton.addEventListener("click", function(){
addItem();
clearText();
});
function clearList(){
var myList = document.getElementById("list");
myList.innerHTML = "";
};
var deleteButton = document.getElementById("deleteAll");
deleteButton.addEventListener("click", clearList);
Commands are fine, I've tested it in console and inputing first
var itemText = document.getElementById("newInput").value;
And then
itemText.innerText = "";
Works just fine, but I cannot get it to work on click event. What am I doing wrong?
Your problem was that you were setting your variable to the value of the textbox, rather than the textbox itself:
function clearText(){
var itemText = document.getElementById("newInput").value; // <----
itemText.innerText = "";
};
This meant that the next line was attempting to set the innerText of the value, which doesn't work. Also, to set or get data to or from an input field, you use the value property. Input fields don't have innerHTML or innerText. In fact, innerText is not even a standard. In places where that makes sense, use textContent instead.
It's always better to set variables to reference DOM elements themselves instead of particular properties of the element. That way, you can access the element and get whatever you need, as often as you need to, without having to re-scan the DOM for the element again when a different property value is needed.
Here's the working code:
function addItem(){
var myList = document.getElementById("list");
var newListItem = document.createElement("li");
var itemText = document.getElementById("newInput").value;
var listText = document.createTextNode(itemText);
newListItem.appendChild(listText);
if (itemText === "") {
alert("Pole nie może być puste");
} else {
myList.appendChild(newListItem);
}
};
function clearText(){
// Just set your variable to the input element, not its value
var itemText = document.getElementById("newInput");
itemText.value = ""; // Form elements have a value property
};
var addButton = document.getElementById("createNew");
addButton.addEventListener("click", function(){
addItem();
clearText();
});
function clearList(){
var myList = document.getElementById("list");
myList.innerHTML = "";
};
var deleteButton = document.getElementById("deleteAll");
deleteButton.addEventListener("click", clearList);
<form class="form">
<input id="newInput" type="text" placeholder="Dodaj pozycję">
<button id="createNew" type="button">Dodaj</button>
</form>
<h2>Moja lista:</h2>
<div class="listBg">
<ul id="list">
</ul>
</div>
<button id="deleteAll" type="button">Wyczyść</button>
Related
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>
I tried to create a function to delete individual list items by using addEventListener to the unordered list which calls a function that checks if the 'delete' button was clicked for that list item. If the 'delete' button was clicked, the function is supposed to delete the list item. But it doesn't seem to be working. Below is the code:
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
<link rel='stylesheet' href='listStyle.css'>
</head>
<body>
<h2 id='heading'>grocery list</h2>
<p>enter item into text box and press "enter" or click "submit".</p>
<p>to remove item, click "remove".</p>
<p>to reset list, click "reset".</p>
<input type = 'text' id = 'item' name = 'item'><br><br>
<button id = 'myBtn' onclick = 'myFunction()'>submit</button>
<button onclick = 'resetFcn()'>reset</button>
</form>
<script>
var str = document.getElementsByTagName('h2');
var strUpper = str[0].innerHTML.toUpperCase();
document.getElementById('heading').innerHTML = strUpper;
var res = document.createElement('ul');
res.setAttribute('id', 'myUL');
res.addEventListener('click', delBtn);
var input = document.getElementById('item');
input.addEventListener('keyup', function(event){
if(event.keyCode===13) {
document.getElementById('myBtn').click();
}
});
function myFunction() {
let x = document.getElementById('item').value;
if (x == '') {
alert ('enter input before submitting');
}
else {
document.body.appendChild(res);
var listItem = document.createElement('li');
const node = document.createTextNode(x);
var btn = document.createElement('button');
btn.innerHTML = 'remove';
btn.setAttribute('id', x);
btn.setAttribute('class', 'delete');
var att= document.createAttribute('style');
att.value = 'float: right';
btn.setAttributeNode(att);
listItem.append(x, ' ');
listItem.appendChild(btn);
res.appendChild(listItem);
item.value = '';
}
}
function resetFcn() {
while (res.firstChild) {
res.removeChild(res.firstChild);
}
}
function delBtn() {
if(event.target.classList.contains('delete')){
event.target.closest('listItem').remove();
}
}
</script>
</body>
</html>
Just add the click handler of the delete button inside your myFunction function:
function myFunction() {
let x = item.value;
if (x == '') {
alert ('enter input before submitting');
}
else {
const listItem = document.createElement('li');
listItem.innerText = x;
const btn = document.createElement('button');
btn.innerText = 'remove';
btn.addEventListener("click", (evt) => {
listItem.remove();
}); //this way you can delete the list item because it is in the same scope
listItem.appendChild(btn);
myUl.appendChild(listItem);
item.value = '';
}
}
This is outside your question but I would also clean up your code, remove the closing form tag, use const/let in stead of var. Do not use keyCode because it is deprecated, ...
I also inserted the ul element in your html:
<ul id="myUl">
</ul>
const myUl = document.getElementById("myUl");
For your reset function you can just set the innerHtml of the ul to an empty string in stead of looping through all the elements:
function resetFcn() {
myUl.innerHTML = "";
}
Hope this helped, good luck!
I'm building a todo app and I use a function to create a list item entered by the user.
There is an event listener added to the output section to listen for a delete button click for each item displayed. My problem is that the delete button is only working for one item and then it stops working.
In the console, it appears that the function is actually called every time I press the button, but the functionality only works for one click. Do I need to add all the list items into an array perhaps?
const todo = document.getElementById('todo');
const enter = document.getElementById('enter');
const output = document.getElementById('output');
enter.addEventListener('click', () => {
listItem(todo);
});
let createListItem;
var deleteBtn;
let checkBtn;
function listItem(todo) {
createListItem = document.createElement('li');
createListItem.innerText = todo.value;
todo.value = '';
output.appendChild(createListItem);
checkBtn = document.createElement('button');
deleteBtn = document.createElement('button');
checkBtn.innerText = 'check';
deleteBtn.innerText = 'delete';
createListItem.append(checkBtn);
createListItem.append(deleteBtn);
checkBtn.classList.add('checkBtn');
deleteBtn.classList.add('deleteBtn');
}
output.addEventListener('click', deleteFunc);
function deleteFunc() {
console.log('function called');
createListItem.remove();
}
<section class="controls">
<div>
<label for="todo">Enter a to-do</label>
<input type="text" name="todo" id="todo">
</div>
<span>
<button id="enter" class = "enter"><i class="fas fa-paper-plane"></i></button>
</span>
</section>
<section>
<ul id="output" class="output">
</ul>
</section>
You need to delegate and use relative addressing because your code only removes the LAST added LI
The variable createListItem pollutes the global scope. Add the keyword var or let in the listItem function too
function deleteFunc(e) {
console.log('function called');
const tgt = e.target;
if (e.target.innerText==="delete") tgt.closest("li").remove()
}
Added benefit from this delegation is that adding the functionality to the "check" button is just
if (e.target.innerText==="check") ...
I would recommend to use a class and testing
if (e.target.classList.contains("delete")
instead of the innerText - especially if you want to change language of the button
const todo = document.getElementById('todo');
const enter = document.getElementById('enter');
const output = document.getElementById('output');
enter.addEventListener('click', () => {
listItem(todo);
});
let createListItem;
var deleteBtn;
let checkBtn;
function listItem(todo) {
let createListItem = document.createElement('li'); // use let or var here
createListItem.innerText = todo.value;
todo.value = '';
output.appendChild(createListItem);
checkBtn = document.createElement('button');
deleteBtn = document.createElement('button');
checkBtn.innerText = 'check';
deleteBtn.innerText = 'delete';
createListItem.append(checkBtn);
createListItem.append(deleteBtn);
checkBtn.classList.add('checkBtn');
deleteBtn.classList.add('deleteBtn');
}
output.addEventListener('click', deleteFunc);
function deleteFunc(e) {
console.log('function called');
const tgt = e.target;
if (e.target.innerText==="delete") tgt.closest("li").remove()
}
<section class="controls">
<div>
<label for="todo">Enter a to-do</label>
<input type="text" name="todo" id="todo">
</div>
<span>
<button id="enter" class = "enter"><i class="fas fa-paper-plane"></i></button>
</span>
</section>
<section>
<ul id="output" class="output">
</ul>
</section>
Your createListItem variable is a global that gets set to the most-recently appended item, so the delete function will always delete the most-recent item. Once an element el has already been removed from the DOM tree, el.remove() is a no-op, so it only works once.
To fix, you can either use event delegation as in #mplungjan's answer or assign a unique id to each list item and pass that as a parameter to the function to determine what to delete.
Example of the second approach:
<ul>
<li id="item-0"></li>
<li id="item-1"></li>
<li id="item-2"></li>
</ul>
const deleteById = id => document.querySelector(`#item-${id}`).remove()
First though:
I think os because you are targeting the "ul" instead the "li" elements. Try adding the event listeners to each "li" element with a querySelectorAll() instead of targeting "output" directly.
When you add another item, you call listItem() which sets a new value to createListItem. This means, when you call deleteFunc(), createListItem.remove(); is only executed on the last element you have added. If this item was already removed, your out of luck as well.
function deleteFunc(e) {
console.log('function called');
const { target } = e; // get target
target.closest("li").remove()
}
Remove the listener on output. (This line: output.addEventListener('click', deleteFunc);)
And add the listener to each deleteBtn:
checkBtn.classList.add('checkBtn');
deleteBtn.classList.add('deleteBtn');
deleteBtn.addEventListener('click', deleteFunc);
This might help you:
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
Find the solution.
const todo = document.getElementById('todo');
const enter = document.getElementById('enter');
const output = document.getElementById('output');
enter.addEventListener('click', () => {
listItem(todo);
});
let createListItem;
var deleteBtn;
let checkBtn;
var index = 0;
function listItem(todo) {
createListItem = document.createElement('li');
createListItem.innerText = todo.value;
createListItem.id= 'li' + index;
todo.value = '';
output.appendChild(createListItem);
checkBtn = document.createElement('button');
deleteBtn = document.createElement('button');
checkBtn.innerText = 'check';
deleteBtn.innerText = 'delete';
deleteBtn.id = 'btn' + index;
createListItem.append(checkBtn);
createListItem.append(deleteBtn);
checkBtn.classList.add('checkBtn');
deleteBtn.classList.add('deleteBtn');
deleteBtn.onclick = function() { deleteFunc(this); };
index += 1;
}
//output.addEventListener('click', deleteFunc);
function deleteFunc(e) {
var rowId = e.id.replace('btn','');
var row = document.getElementById('li'+rowId);
console.log('function called' + rowId);
//alert(rowId);
if (row != null) {
row.remove();
}
//console.log('function called');
//createListItem.remove();
}
<section class="controls">
<div>
<label for="todo">Enter a to-do</label>
<input type="text" name="todo" id="todo">
</div>
<span>
<button id="enter" class = "enter"><i class="fas fa-paper-plane"></i></button>
</span>
</section>
<section>
<ul id="output" class="output">
</ul>
</section>
I am trying to be able to add user input into an array. I cannot seem to figure out how to go about accomplishing this. I have spent hours trying to figure out exactly what to do. I also would like to have this "to do list" save to my local storage, I am equally frustrated with trying to figure out both of these issues.
Any advice or guidance on how to add to the array from user input and/or how to put this into local storage would be greatly appreciated. It has taken me quite some time to even get thus far. Thank you for all of your help! Greatly appreciated.
Javascript
var theList = [];
function todoList() {
var item = document.getElementById('todoInput').value;
var text = document.createTextNode(item);
var checkbox = document.createElement('input');
checkbox.type = "checkbox";
checkbox.name = "name";
checkbox.value = "value";
var newItem = document.createElement("li");
newItem.appendChild(checkbox);
newItem.appendChild(text);
document.getElementById("todoList").appendChild(newItem)
return clear();
}
function clear() {
todoInput.value = "";
}
console.log(theList);
HTML
<h1>To Do List:<h1>
<input id="todoInput" type="text">
<button type="button" onclick="todoList()">Add Item</button>
</form>
<ol id="todoList">
</ol>
<script src="todo.js"></script>
To add the newly created list-item, just add theList.push(item) to your todoList() function.
To save the var theList = [] array to localStorage use:
localStorage.setItem("todoList", JSON.stringify(theList));
And use this to retrieve the localStroage object:
var storedTodoList = JSON.parse(localStorage.getItem("todoList"));
See the snippet below:
<h1>To Do List:</h1>
<input id="todoInput" type="text">
<button type="button" onclick="todoList()">Add Item</button>
<ol id="todoList">
</ol>
<script>
var theList = [];
function todoList() {
var item = document.getElementById('todoInput').value;
var text = document.createTextNode(item);
var checkbox = document.createElement('input');
checkbox.type = "checkbox";
checkbox.name = "name";
checkbox.value = "value";
var newItem = document.createElement("li");
newItem.appendChild(checkbox);
newItem.appendChild(text);
document.getElementById("todoList").appendChild(newItem);
theList.push(item); // This adds the item to theList[]
//localStorage.setItem("todoList", JSON.stringify(theList)); // Set localStorage object
//var storedTodoList = JSON.parse(localStorage.getItem("todoList")); // Get localStorage object
console.log(theList);
return clear();
}
function clear() {
todoInput.value = "";
}
</script>
<!-- <script src="todo.js"></script> -->
Hope this helps.
If you don't mind using jQuery the following should be good enough - either way it's not very difficult to convert to JavaScript.
Here is a fiddle with a working to do list - https://jsfiddle.net/makzan/bNQ7u/
$('#add-btn').click(function(){
// get value from #name input
var val = $('#name').val();
// append the name to the list
$('#list').append("<li>" + val + " <a href='#' class='done-btn'>Done</a> <a href='#' class='cancel-btn'>Cancel Task</a></li>");
// reset the input field and focus it.
$('#name').val("").focus();
});
// correct approach
$('.done-btn').live( 'click', function() {
$(this).parent('li').addClass('done');
});
$('.cancel-btn').live( 'click', function() {
$(this).parent('li').fadeOut();
});
As you can see, the logic is to simply assign listeners which are handled much simpler in jQuery
I'm building a small to do list and everything worked fine so far until I included a checkbox. now when I click on the button, nothing happens and neither do I see a checkbox. There must be something wrong with the order of code-does someone know how I need to rearrange the code and WHY?
Html code:
<body>
<h1>To Do List</h1>
<p><input type="text" id="textItem"/><button id="add">Add</button></p>
<ul id="todoList">
</ul>
</body>
Javascript code:
function addItem() {
var entry = document.createElement("li");
var checkBox = document.getElementById("input");
checkBox.type = "checkbox";
var span = document.createElement("span");
span.innerText = entry;
var textItem = document.getElementById("textItem");
entry.innerText = textItem.value;
var location = document.getElementById("todoList");
entry.appendChild(checkBox);
entry.appendChild(span);
location.appendChild(entry);
}
var item = document.getElementById("add");
item.onclick = addItem;
UPDATED - I've spotted 4 issues . Follow Below :
1st : When you create the check box you should be using setAttribute method to specify input type : checkbox.setAttribute("type" , "checkbox")
2nd : Your checkbox variable should be creating an input element : var checkBox = document.createElement("input");
3rd : You should be using innerHtml instead of innerText as you are referencing a list ELEMENT stored in your entry variable : span.innerHtml = entry;
4th: Really minor but you should grab your item and attach an event to the item before your function :
var item = document.getElementById("add");
item.addEventListener("click" , addItem)
Just change your javascript to the following :
var item = document.getElementById("add");
item.addEventListener("click" , addItem)
function addItem() {
var entry = document.createElement("li");
var checkBox = document.createElement("input");
checkBox.setAttribute("type" , "checkbox");
var span = document.createElement("span");
span.innerHtml = entry;
var textItem = document.getElementById("textItem");
entry.innerText = textItem.value;
var location = document.getElementById("todoList");
entry.appendChild(checkBox);
entry.appendChild(span);
location.appendChild(entry);
}
Example Here : http://codepen.io/theConstructor/pen/pyPdgg
Good Luck!