Deleting last item on the list - javascript

I have a simple HTML unordered list and a JavaScript function that adds items at position [0], and another that deletes items at [0] as well, but what can I add to the delete function (strictly basic JavaScript please even if it's longer) so it deletes the last added item? Thank you in advance:
HTML:
<html>
<body>
<h1> Shopping List </h1>
<button onclick="adding()"> Add </button>
<input type="text" id="input" placeholder="Enter Items"> </input>
<button onclick="remove()"> Remove Last </button>
<ul id="list">
</ul>
</body>
</html>
Javascript:
function adding() {
var input = document.getElementById("input").value;
var newEl = document.createElement("li");
var newText = document.createTextNode(input);
newEl.appendChild(newText);
var position = document.getElementsByTagName("ul")[0];
position.appendChild(newEl);
document.getElementById("input").value = "";
}
function remove() {
var removeEl = document.getElementsByTagName("li")[0];
var containerEl = removeEl.parentNode;
containerEl.removeChild(removeEl);
}

function adding() {
var input = document.getElementById("input").value;
var newEl = document.createElement("li");
var newText = document.createTextNode(input);
newEl.appendChild(newText);
var position = document.getElementsByTagName("ul")[0];
position.appendChild(newEl);
document.getElementById("input").value = "";
}
function remove() {
var els = document.getElementsByTagName("li");
var removeEl = els[els.length - 1]; // <-- fetching last el
var containerEl = removeEl.parentNode;
containerEl.removeChild(removeEl);
}
<html>
<h1> Shopping List </h1>
<button onclick="adding()"> Add </button>
<input type="text" id="input" placeholder="Enter Items"> </input>
<button onclick="remove()"> Remove Last </button>
<ul id="list">
</ul>
</body>
</html>
If els is an array, it has indices from 0 to els.length - 1. 0 is the first, els.length - 1 is the last index.
Besides, try not to use attribute event handlers like onclick="adding()". A much better practice is to attach them programmatically, for clean separation of concerns:
<button id="add">Add</button>
and then
document.getElementById('add').addEventListener('click', adding);

Purely speaking this answers the question as it only removes the last added item then won't remove anything else
window.lastadded = false;
function adding() {
var input = document.getElementById("input").value;
var newEl = document.createElement("li");
newEl.id = Date.parse(new Date());
var newText = document.createTextNode(input);
window.lastadded = newEl.id;
newEl.appendChild(newText);
var position = document.getElementsByTagName("ul")[0];
position.appendChild(newEl);
document.getElementById("input").value = "";
}
function remove() {
lastElement = document.getElementById(window.lastadded);
lastElement.parentNode.removeChild(lastElement);
}

Related

Trying to delete todo list but not working

var inputItem = document.getElementById("inputItem");
function addItem(list, input) {
var inputItem = this.inputItem;
var list = document.getElementById(list);
var listItem = document.createElement("li");
var deleteButton = document.createElement("button");
deleteButton.innerText = "delete";
deleteButton.addEventListener("click", function() {
//console.log("Delete");
//var ul=document.getElementById("list");
var listItem = list.children;
for (var i=0; i < listItem.length; i++) {
while(listItem[i] && listItem[i].children[0].checked) {
ul.removeChild(listItem[i]);
}
}
});
var checkBox = document.createElement("input");
checkBox.type = 'checkbox';
var label = document.createElement("label");
var labelText = document.createElement("span");
labelText.innerText = input.value;
label.appendChild(checkBox);
label.appendChild(labelText);
listItem.appendChild(label);
listItem.appendChild(deleteButton);
list.appendChild(listItem);
inputItem.focus();
inputItem.select();
return false;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>To-Do List</title>
</head>
<body>
<h1>To-Do List</h1>
<form onsubmit="return addItem('list', this.inputItem)">
<input type="text" id="inputItem">
<input type="submit">
</form>
<ul id="list">
</ul>
</body>
</html>
So first of all, there are a few little mistakes in the code:
var list = document.getElementById(list); - You're using the list as the parameter, not a string.
while(listItem[i] && listItem[i].children[0].checked) { - Not sure why you're using while here instead of if.
ul.removeChild(listItem[i]); - ul is commented a few lines above.
Besides these, the delete does not work because of the following line:
if(listItem[i] && listItem[i].children[0].checked) {
If you analyze the DOM, the list item contains a <label></label> that contains the input, which means children[0] is not what you expect it to be.
Therefore, fixing the issues mentioned above and replacing the check in the delete callback function with
if(listItem[i] && listItem[i].getElementsByTagName('input')[0].checked) {
list.removeChild(listItem[i]);
}
should be your fix.

Added text strings do not show in unordered list

I'm trying to code a small application that lets you dynamically add text strings in an unordered list, but the problem is the strings I pass as input do not show up after clicking the "Invia/Send" button. I have tried with a few solutions from other questions, but none of them worked. Any ideas?
<html>
<head>
<title>Promemoria esercizi</title>
</head>
<body>
<ul id="paragraphList">
</ul>
<form id="paragraphForm">
<br></br>
<textarea id="insertParagraph" rows="5" cols="100"></textarea>
<label>Inserisci il paragrafo:
<input type="radio" id="insertType" name="InsertType" value="last">In fondo
<input type="radio" id="insertType" name="InsertType" value="before">Dietro il paragrafo
<select id="beforeParagraph"></select><br></br>
</label>
<button id="add" onclick="addParagraph(paragraphArray)">Inserisci</button><br></br>
</form>
<script>
var paragraphArray = [];
document.getElementById("paragraphList").innerHTML = paragraphArray;
function addParagraph(paragraphArray){
var text = document.getElementById("insertParagraph").value;
var radio = document.getElementById("insertType");
var selectedInsertType = "";
var ul = document.getElementById("paragraphList");
var sel = document.getElementById("beforeParagraph");
var selectedBeforeParagraph = sel.options[sel.selectedIndex].value;
for(i = 0; i < radio.length; i++){
if(radio[i].checked){
selectedInsertType = radio[i].value;
}
}
if(selectedInsertType = "last"){
paragraphArray.push(text);
}else if(selectedInsertType = "before"){
paragraphArray.splice((selectedBeforeParagraph-1), 0, text);
}
var newChoice = document.createElement("option");
newChoice.value = paragraphArray.length.toString();
newChoice.text = paragraphArray.length.toString();
for(i = 0; i < paragraphArray.length; i++){
var li = document.createElement("li");
li.innerHTML = paragraphArray[i];
}
document.getElementById("paragraphList").innerHTML = paragraphArray;
}
</script>
</body>
</html>
There were a few issues:
A common problem people run into with the button tag is by default, it has a type of 'submit' which will submit the form. There are a few ways to disable this, my preferred method is to set the type as button.
Another issue is you don't have any content in the select box, which was causing an error trying to get the value of a select box with no options that can be selected.
I updated your radios, to use querySelectorAll and look for :checked that way you don't need to create an if statement.
I also removed the paragraphArray from addParagraph() since it is a global variable.
<html>
<head>
<title>Promemoria esercizi</title>
</head>
<body>
<ul id="paragraphList">
</ul>
<form id="paragraphForm">
<br></br>
<textarea id="insertParagraph" rows="5" cols="100"></textarea>
<label>Inserisci il paragrafo:
<input type="radio" id="insertType" name="InsertType" value="last">In fondo
<input type="radio" id="insertType" name="InsertType" value="before">Dietro il paragrafo
<select id="beforeParagraph"></select><br></br>
</label>
<button type="button" id="add" onclick="addParagraph()">Inserisci</button><br></br>
</form>
<script>
var paragraphArray = [];
document.getElementById("paragraphList").innerHTML = paragraphArray;
function addParagraph(){
var text = document.getElementById("insertParagraph").value;
var radio = document.querySelectorAll("#insertType:checked");
var selectedInsertType = "";
var ul = document.getElementById("paragraphList");
var sel = document.querySelector("#beforeParagraph");
var selectedBeforeParagraph = (sel.selectedIndex > -1) ? sel.options[sel.selectedIndex].value : "";
for(i = 0; i < radio.length; i++){
selectedInsertType = radio[i].value;
}
if(selectedInsertType = "last"){
paragraphArray.push(text);
}else if(selectedInsertType = "before"){
paragraphArray.splice((selectedBeforeParagraph-1), 0, text);
}
var newChoice = document.createElement("option");
newChoice.value = paragraphArray.length.toString();
newChoice.text = paragraphArray.length.toString();
for(i = 0; i < paragraphArray.length; i++){
var li = document.createElement("li");
li.innerHTML = paragraphArray[i];
}
document.getElementById("paragraphList").innerHTML = paragraphArray;
}
</script>
</body>
</html>

Word count limit for multiple textarea tags

I have this script to limit the words on a textarea but I want to use the same function to a form that contains multiple textarea tags.
What is the best way to reuse this and make an independent word counter and limiter for every textarea tag in the same form?
Thanks a lot in advance.
var wordLimit = 5;
var words = 0;
var jqContainer = $(".my-container");
var jqElt = $(".my-textarea");
function charLimit()
{
var words = 0;
var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
words = wordmatch?wordmatch.length:0;
if (words > wordLimit) {
var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = jqElt.val()[trimmed.length];
jqElt.val(trimmed + lastChar);
}
$('.word-count', jqContainer).text(words);
$('.words-left', jqContainer).text(Math.max(wordLimit-words, 0));
}
jqElt.on("keyup", charLimit);
charLimit();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
<textarea class="my-textarea"></textarea>
<span class="words-left"></span> words left
<div>
You can use a generic function ($this) is the textarea element changed.
For relative elements, you can use the function .next(selector)
Also you can read parameters from attributes (maxwords for example).
var jqContainer = $(".my-container");
function charLimit()
{
var words = 0;
var jqElt=$(this);
var wordLimit = jqElt.attr("maxwords");
var words = 0;
var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
words = wordmatch?wordmatch.length:0;
if (words > wordLimit) {
var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = jqElt.val()[trimmed.length];
jqElt.val(trimmed + lastChar);
}
jqElt.next('.words-left').text(Math.max(wordLimit-words, 0));
}
$(".my-textarea", jqContainer).on("keyup", charLimit).keyup();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
<textarea id="text1" class="my-textarea" maxwords="5"></textarea>
<span class="words-left"></span> words left
<textarea id="text1" class="my-textarea" maxwords="10"></textarea>
<span class="words-left"></span> words left
<div>
You can wrap your logic up in a function and reuse that function.
See example:
function wordCounter(container, limit) {
var wordLimit = limit;
var jqContainer = $(container);
var jqElt = $("textarea", jqContainer);
function charLimit()
{
var words = 0;
var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
words = wordmatch?wordmatch.length:0;
if (words > wordLimit) {
var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = jqElt.val()[trimmed.length];
jqElt.val(trimmed + lastChar);
}
$('.word-count', jqContainer).text(words);
$('.words-left', jqContainer).text(Math.max(wordLimit-words, 0));
}
jqElt.on("keyup", charLimit);
charLimit();
}
wordCounter(".my-container1", 5);
wordCounter(".my-container2", 10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container1">
<textarea class="my-textarea"></textarea>
<span class="words-left"></span> words left
</div>
<div class="my-container2">
<textarea class="my-textarea"></textarea>
<span class="words-left"></span> words left
</div>
Note that you had an issue in your example where the div tag wasn't closed.
if you need to use that same implementation you could add an id to each text area you are going to put in the form, then add an attribute for= to the corresponding spans pointing to the corresponding text area like this:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
<textarea id="textarea-1" class="my-textarea" onkeyup="charLimit(this)"></textarea>
<span for="textarea-1" class="words-left"></span> words left
<textarea id="textarea-2" class="my-textarea" onkeyup="charLimit(this)"></textarea>
<span class="words-left" for="textarea-2"></span> words left
<div>
var wordLimit = 5;
var words = 0;
var jqContainer = $(".my-container");
function charLimit(elem)
{
var elm = $(elem)
var words = 0;
var wordmatch = elm.val().match(/[^\s]+\s+/g);
words = wordmatch?wordmatch.length:0;
if (words > wordLimit) {
var trimmed = elm.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = elm.val()[trimmed.length];
elm.val(trimmed + lastChar);
}
$('.word-count', jqContainer).text(words);
$('[for='+ elm.attr('id') +']', jqContainer).text(Math.max(wordLimit-words, 0));
}
This is how I will normally do it:
Create a function that handles the word count refreshMaxWords()
Create a hook that can be tied up with the element <textarea data-max-words="5"></textarea>
(function($) {
var refreshMaxWords = function ($el) {
var wordLimit = parseInt($el.data('max-words')) || false,
wordmatch = $el.val().match(/[^\s]+\s+/g),
words = wordmatch ? wordmatch.length : 0,
// You can change how to get the "words-left" div here
$wordsLeft = $el.parent().find('.words-left');
if (wordLimit !== false) {
if (words > wordLimit) {
var trimmed = $el.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = $el.val()[trimmed.length];
$el.val(trimmed + lastChar);
}
}
if ($wordsLeft.length > 0) {
$wordsLeft.html(Math.max(wordLimit - words, 0));
}
};
$(function () {
$(document).on('keyup.count-words', '[data-max-words]', function (e) {
refreshMaxWords($(this));
});
});
})(jQuery);
This is with assumption of HTML that looks like the following:
<div class="form-group">
<label>Input #1</label>
<textarea class="form-control" data-max-words="5"></textarea>
<p class="help-block"><span class="words-left">5</span> words left.</p>
</div>
<div class="form-group">
<label>Input #2</label>
<textarea class="form-control" data-max-words="10"></textarea>
<p class="help-block"><span class="words-left">10</span> words left.</p>
</div>
The benefits of this approach are:
Cleaner code structure
This can be reused on your other projects.
Notes:
You don't really need to wrap the javascript in
(function($) {
// your code here
})(jQuery);
I like doing it because it ensures that there won't be any conflict by accident.

Cannot remove list item from ul todo list

I tried to remove the list item inside ul with querySelectorAll and remove going through each li element. Where is the mistake please, and how is it fixed?
<div class='container'>
<h1> New todo list</h1>
<form>
<input type= 'text' id='item'
required>
<ul> </ul>
<button id='button'> clear all</
button>
</div>
Here's the code:
var form =
document.querySelector('form')
var ul = document.querySelector('ul')
var button =
document.querySelector(#button)
var input =
document.querySelector('item')
var liMaker = text => {
var li =
document.createElement('li')
li.textContent = text
ul.insertBefore(li,
ul.childNodes[0])
button.onclick = remove
}
form.addEventListener('submit',
function(e){
e.preventDefault()
liMaker(input.value)
input.value = ' '
})
function remove(e){
Array.from(
document.querySelectorAll('
li')).forEach(item =>
e.target.item.remove())
}
I have edited your code a little and added a new button to keep the functionality separate. I think this is the kind of functionality you were after if I understood your question correctly.
<div class='container'>
<h1> New todo list</h1>
<form>
<input type='text' id='item' required>
<ul id="myList"></ul>
<button id='button'>add</button>
</form>
<button id="clear">Clear</button>
</div>
JS:
var form = document.querySelector('form')
var ul = document.querySelector('ul')
var button = document.querySelector('#button');
var input = document.querySelector('#item');
var clear = document.querySelector('#clear');
var liMaker = text => {
var li = document.createElement('li');
li.textContent = text;
ul.insertBefore(li, ul.childNodes[0])
}
form.addEventListener('submit', function(e) {
e.preventDefault()
liMaker(input.value)
input.value = '';
});
clear.addEventListener('click', remove);
function remove(){
saveToDos();
while (ul.firstChild) {
ul.removeChild(ul.firstChild);
}
}
function saveToDos() {
var items = ul.getElementsByTagName("li");
for (var i = 0; i < items.length; ++i) {
savedToDos.push(items[i].innerHTML);
}
localStorage.setItem('savedValues', savedToDos);
}
Here is a link to a working pen: https://codepen.io/caeking/pen/RzyKmV

Removing elements from the DOM by their ID, not Index

I am making a generic todolist, the problem with my todolist is that it removes elements based on their INDEX while it takes their ID to get a position to delete
(example: let's say I add 6 items in my todolist, they all have an id from 1 to 6, if I remove 3 and 4, and then I try to remove 6, it won't work, because it tries taking the ID of element 6 which is 6 but it tries to delete the item at index 6 instead of ID 6)
Please help me remove them based on their ID and not index but I want it with PLAIN javascript, not jQuery, thank you.
ul.addEventListener("click", function(event){
console.log(event.target.parentNode.id);
if (event.target.className === "buttonClass"){
for (let z = 0; z < ul.children.length; z++){
let eh = event.target.parentNode.id;
ul.children.getAttribute("id")[eh].remove()
}
}
}
While i think this code is enough, I will add all of it below it
let ul = document.querySelector("ul")
let li = document.querySelectorAll("li");
let selectInput = document.querySelector("input");
let createLi = function(){
let createLi = document.createElement("li");
let addNow = ul.appendChild(createLi);
addNow.textContent = selectInput.value;
selectInput.value = "";
let btn = document.createElement("button");
let createButton = addNow.appendChild(btn);
createButton.textContent = "Button";
createButton.setAttribute("class", "buttonClass");
for(let i = 0; i < ul.children.length; i++){
addNow.setAttribute("id", i)
}
};
HTML BELOW
<button id="main" onclick="createLi()"> add</button>
<input type="text" class="input">
<ul>
</ul>
You can get your li element by its ID and remove it or Just use remove to the parent element which is the same li tag:
ul.addEventListener("click", function(event){
let id = event.target.parentNode.id;
document.getElementById(id).remove();
// Or directly
event.target.parentNode.remove();
});
Here is an example:
let ul = document.querySelector("ul")
let li = document.querySelectorAll("li");
let selectInput = document.querySelector("input");
let createLi = function() {
let createLi = document.createElement("li");
let addNow = ul.appendChild(createLi);
addNow.textContent = selectInput.value;
selectInput.value = "";
let btn = document.createElement("button");
let createButton = addNow.appendChild(btn);
createButton.textContent = "Button";
createButton.setAttribute("class", "buttonClass");
for(let i = 0; i < ul.children.length; i++){
addNow.setAttribute("id", i);
}
};
ul.addEventListener("click", function(event){
console.log(event.target.parentNode.id);
event.target.parentNode.remove();
});
<button id="main" onclick="createLi()"> add</button>
<input type="text" class="input">
<ul>
</ul>
Id is not needed to remove element:
<u onclick=this.parentNode.removeChild(this)> Click to remove </u>
or event.target to get the element that as clicked:
<ul onclick=event.target.parentNode.removeChild(event.target)>
<li> Item 1 </li>
<li> Item 2 </li>
<li> Item 3 </li>
<li> Item 4 </li>
</ul>
Bonus: It can even be faked with CSS (but JavaScript is still needed to add nodes) :
<style>[type], :checked + * { display: none }</style>
<input id=i><button onclick="i.value&&body.insertAdjacentHTML('beforeend', `<input type=
checkbox id=${n=Date.now()}><label for=${n}>${i.value}<br></label>`)">Add</button><br>
<input type=checkbox id=1><label for=1> Item 1 <br></label>
<input type=checkbox id=2><label for=2> Item 2 <br></label>
<input type=checkbox id=3><label for=3> Item 3 <br></label>
<input type=checkbox id=4><label for=4> Item 4 <br></label>

Categories

Resources