Add/Remove item list - javascript

I'm practicing with javascript. I built a grocery list in which I would like to add and remove items. Adding elements works fine by typing a name in a input form and pushing the send button. I'd like to remove the element that I just created by clicking on it but I get this error instead:
"Uncaught TypeError: Cannot read property 'removeChild' of undefined at HTMLDocument.removeItem"
here the code:
HTML:-
<div id="paper">
<h3 id="title">Groceries list:</h3>
<ul id="list">
<li></li>
</ul>
</div>
<p class="grocery">
<input type="text" name="grocery" placeholder="ex. Apple" id="blank" />
<label for="grocery">Grocery Name</label>
</p>
<p class="submit">
<input type="submit" value="SEND" id="btn" />
</p>
<script type="text/javascript" src="js/script.js"></script>
CSS:-
#paper {
width: 300px;
height: auto;
margin: 20px auto;
clear: both;
background-color: orange;
}
.grocery, .submit{
text-align: center;
margin: 20px;
}
Javascript:-
var elList = document.getElementById("list");
var elButton = document.getElementById("btn");
function addItem(e) {
var elElement = document.createElement("li");
var whatever = el.value;
var elText = document.createTextNode(whatever);
elElement.appendChild(elText);
elList.appendChild(elElement);
}
function removeItem(e) {
var elElement = document.getElementsByTagName("li");
var elContainer = elElement.parentNode;
elContainer.removeChild(elElement);
}
var el = document.getElementById("blank");
elButton.addEventListener("click", addItem, false);
if ("DOMNodeInserted") {
document.addEventListener("click", removeItem, false);
}
How could I get through this?
Thank you guys for your help

if ("DOMNodeInserted") {
document.addEventListener("click", removeItem, false);
} is wrong. you need to attach this event handler to each list you create.
you can do that in addItem() using elElement.addEventListener("click", removeItem, false);, then in removeItem(e) just use e to get current element using e.currentTarget and remove it.
This seems to work:
var elList = document.getElementById("list");
var elButton = document.getElementById("btn");
function addItem(e) {
var elElement = document.createElement("li");
var whatever = el.value;
var elText = document.createTextNode(whatever);
elElement.appendChild(elText);
elList.appendChild(elElement);
elElement.addEventListener("click", removeItem, false);
}
function removeItem(e) {
var elElement = e.currentTarget;
var elContainer = elElement.parentNode;
elContainer.removeChild(elElement);
}
var el = document.getElementById("blank");
elButton.addEventListener("click", addItem, false);
#paper {
width: 300px;
height: auto;
margin: 20px auto;
clear: both;
background-color: orange;
}
.grocery, .submit{
text-align: center;
margin: 20px;
}
<div id="paper">
<h3 id="title">Groceries list:</h3>
<ul id="list">
<li></li>
</ul>
</div>
<p class="grocery">
<input type="text" name="grocery" placeholder="ex. Apple" id="blank" />
<label for="grocery">Grocery Name</label>
</p>
<p class="submit">
<input type="submit" value="SEND" id="btn" />
</p>

Your problem is here:
function removeItem(e) {
var elElement = document.getElementsByTagName("li");
var elContainer = elElement.parentNode;
elContainer.removeChild(elElement);
}
This document.getElementsByTagName return an HTMLElementCollection which does not have the a property called parentNode. An element from that collection would.
To avoid the undefined error, you need to check if your object is null or undefined before trying to call a method on in such as .removeChild.
In your case, elContainer is null because the elElement is an HTMLElementCollection which doesn't have the .parentNode property.
You can access elements in the collection by index. It also has a length property which you should check to make sure that the collection has elements.
So if you want to remove the first LI, they you can do it like this.
function removeItem(e) {
var elements= document.getElementsByTagName("li");
if (elements.length==0) return;
var elElement = elements[0];
var elContainer = elElement.parentNode;
elContainer.removeChild(elElement);
}
So if you want to remove the that last LI, they you can do it like this.
function removeItem(e) {
var elements= document.getElementsByTagName("li");
if (elements.length==0) return;
var elElement = elements[elements.length-1];
var elContainer = elElement.parentNode;
elContainer.removeChild(elElement);
}

Related

changing the content of a div

I would like to change the content of a div. I have three divs:
<div
class="box1"
style="height: 200px; width: 200px; background-color: red"
>
A
</div>
<br />
<div
class="box2"
style="height: 200px; width: 200px; background-color: blue"
>
<label for="">tex</label>
<input type="text" />
</div>
<br />
<div
class="box3"
style="height: 200px; width: 200px; background-color: yellow"
>
C
</div>
when the page is ready the 2 and 3rd box displays none:
function hideElementBoxOnLoad() {
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
box2.style.display = "none";
box3.style.display = "none";
}
$(document).ready(hideElementBoxOnLoad);
I want a click that toggles the content of box2 and box3 into box1 and then back to box1 content:
function changeContent() {
let chang = true;
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
let box2Content = box2.textContent;
let box3Content = box3.textContent;
if (chang) {
box1.textContent = box2Content;
chang = !chang;
if ((box1.textContent === box2Content)) {
box1.textContent = box3Content;
}
}
}
let btn = document.getElementById("btn");
btn.addEventListener("click", changeContent);
So far it worked but it does not display the content of box2 only box3. what did i do wrong and what better way can i toggle with a boolean.
See below
Instead of trying to swap content between each div just use JS to go through the array of them and swap an active class between them;
var boxes = document.getElementsByClassName('box');
var change = document.getElementById('change');
var counter = 0;
change.addEventListener('click', function(){
boxes[counter].classList.remove('active');
boxes[counter].nextElementSibling.classList.add('active');
counter++;
if(counter === boxes.length) {
counter = 0;
boxes[0].classList.add('active');
}
});
.box {
display: none;
width: 100px;
height: 100px;
background-color: gray;
}
.box.active {
display:block
}
<div class="box active">A</div>
<div class="box">B</div>
<div class="box">C</div>
<button id="change">Change Content</button>
im not completely sure if i understood ur question.
but below u can see and even test with the snippet button.
the button now add what ever content in in the yellow box, and whats in the input field of the blue box into the red box. listing them downwards.
if you want to replace the content completely.
just change the logic to box1.innerHTML += spacer+box3.innerHTML+spacer+input.value
this is the most simple way to do it thats easy to understand just by reading the code i think.
hope this helps!
function changeContent() {
//the button
const btn = document.getElementById("btn");
//the boxes
const box1 = document.getElementById("box1");
const box2 = document.getElementById("box2");
const box3 = document.getElementById("box3");
//a spacer
const spacer = "<br>";
//the input field
const input = document.getElementById("input");
//logic
box1.innerHTML += spacer+box3.innerHTML+spacer+input.value
}
div{
border-radius: 5px;
text-align: center;
font-family: sans-serif;
}
#box1{
min-height: 200px;
width: 200px;
padding: 5px;
background-color: rgb(255, 73, 73);
}
#box2 {
height: 200px;
width: 200px;
padding: 5px;
background-color: rgb(0, 195, 255);
}
#box3 {
height: 200px;
width: 200px;
padding: 5px;
background-color: yellow;
}
button{
padding: 3px;
margin-top: 10px;
}
<div id="box1">
<p>contetnt A</p>
</div>
<br />
<div id="box2" >
<label for="">tex</label>
<input id="input" type="text" />
<button id="btn" onclick="changeContent()">click me</button>
</div>
<br />
<div id="box3">
contetnt C
</div>
List of bugs :-
You had declared the var chang locally instead of globally, which make it true whenever you runs the function.
You are directly writing value from one tag to another, which causing the data loss, when you run your function second time.
For example :- When you click the button first time, the data is swapped, but for the second click, the data first div is lost and cannot be brought back...
Solution :- Store the data in an array in document.ready event handler and extract data from the array to update you html tags.
function hideElementBoxOnLoad() {
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
box2.style.display = "none";
box3.style.display = "none";
content = [box1.textContent, box2.textContent, box3.textContent];
let btn = document.getElementById("btn");
btn.addEventListener("click", changeContent);
}
var content = [];
window.onload = (hideElementBoxOnLoad);
var index = 0;
function changeContent() {
let chang = true;
let box1 = document.querySelector(".box1");
/* let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
let box2Content = box2.textContent;
let box3Content = box3.textContent;
if (chang) {
box1.textContent = box2Content;
chang = !chang;
if ((box1.textContent === box2Content)) {
box1.textContent = box3Content;
}
}
*/
function cycle(n, x = 0, y = content.length - 1, a = 1) {
n += a;
if (n > y) return x;
if (n < x) return y;
return n;
}
index = cycle(index);
box1.textContent = content[index];
}
<div class="box1" style="height: 200px; width: 200px; background-color: red">
A
</div>
<br />
<div class="box2" style="height: 200px; width: 200px; background-color: blue">
<label for="">tex</label>
<input type="text" />
</div>
<br />
<div class="box3" style="height: 200px; width: 200px; background-color: yellow">
C
</div>
<button id="btn"> CLICK ME </button>
Explaination
Here I first stored the tags textContent in a array content, in the starting of the code.
Then, inside the button click handler, a simple cycle function to cycle on the values stored inside the content array.

JavaScript Function

Hello everybody I have this code that I have made alone.
function appearafter() {
document.getElementById("buttonappear").style.display = "block";
document.getElementById("button").style.display = "block";
document.getElementById("hinzufuegen").style.display = "none";
function myFunction() {
var itm = document.getElementById("myList2").lastChild;
var cln = itm.cloneNode(true);
document.getElementById("myList1").appendChild(cln);
}
function allFunction() {
myFunction();
appearafter();
}
#button {
display: none;
}
#buttonappear {
display: none;
}
#test {
width: 300px;
height: 300px;
background-color: red;
}
<!DOCTYPE html>
<html>
<body>
<button id="hinzufuegen" onclick="allFunction()">ADD</button>
<div id="myList1">
<button id="button" onclick="">DELETE</button>
<div id="myList2">
<div id="test">
</div>
</div>
</div>
<button onclick="allFunction()" id="buttonappear">ADD</button>
</body>
</html>
What I want to make is that the red square whenever you are clicking on the ADD button it will be a clone and when you click on the DELETED button that the clone is deleted. Can somebody help me, please?
In addition to missing } as was mentioned in the comments, there was a not-so-obvious problem with finding the <div> to clone. The lastChild was actually a text node containing the \n (newline), after the <div>. It's better to search for <div> by tag:
var itm = document
.getElementById('myList2')
.getElementsByTagName('div')[0];
Since there's only one <div> we can use the zero index to find this first and only one.
And for delete function you can use a similar approach and get the last <div> and remove it.
function appearafter() {
document.getElementById("buttonappear").style.display = "block";
document.getElementById("button").style.display = "block";
document.getElementById("hinzufuegen").style.display = "none";
}
function myFunction() {
var itm = document.getElementById("myList2").getElementsByTagName("div")[0];
var cln = itm.cloneNode(true);
document.getElementById("myList1").appendChild(cln);
}
function deleteFunction() {
var list1 = document.getElementById("myList1");
var divs = Array.from(list1.getElementsByTagName("div"));
// If the number of divs is 3, it means we're removing the last
// cloned div, hide the delete button.
if (divs.length === 3) {
document.getElementById("button").style.display = "none";
}
var lastDivToDelete = divs[divs.length - 1];
list1.removeChild(lastDivToDelete);
}
function allFunction() {
myFunction();
appearafter();
}
#button {
display: none;
}
#buttonappear {
display: none;
}
#test {
/* make it smaller so it's easier to show in a snippet */
width: 30px;
height: 30px;
background-color: red;
}
<button id="hinzufuegen" onclick="allFunction()">ADD</button>
<div id="myList1">
<button id="button" onclick="deleteFunction()">DELETE</button>
<div id="myList2">
<div id="test"></div>
</div>
</div>
<button onclick="allFunction()" id="buttonappear">ADD</button>

Pushing values into an empty array?

I'm recently new at programming and JavaScript. I'm not sure why this doesn't work. I'm trying to insert numbers into an empty array. And then have them displayed into the div with the id of "value".
My JavaScript:
var array = new Array();
// var array = [];
$(document).ready(function() {
$('#btn').on('click', function() {
var $input = $('#input').val();
array.push($input);
});
$('#value').text(array);
console.log(array);
});
My HTML:
<div id="number">
<input type="text" id="input">
<button id="btn"> Submit </button>
</div>
You render the empty array once, when the document is ready. Adding more items to the array doesn't rerender the DOM with the new items. You need to update the DOM on each click by moving $('#value').text(array); into the click event handler:
var array = new Array();
// var array = [];
$(document).ready(function() {
var $input = $('#input');
var $value = $('#value');
$('#btn').on('click', function() {
var val = $input.val();
array.push(val);
$value.text(array);
console.log(array);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="input">
<button id="btn">Add</button>
<div id="value"></div>
Just a reminder that Input Fields supply a String not an Integer.
Take a look:
var myArray = [];
$(function() {
$('#btn').on('click', function() {
var $input = $('#input').val();
myArray.push(parseInt($input));
console.log(myArray)
$('#value').text("[" + myArray.join(", ") + "]");
});
});
.input {
padding: 10px;
font-family: Arial, Helvetica, sans-serif;
font-size: 1em;
}
.input input {
width: 60px;
height: 1.25em;
}
.input button {
padding: .25em .6em;
}
.output {
font-family: Arial, Helvetica, sans-serif;
font-size: 1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="input">
<input type="number" id="input" /> <button id="btn">Add</button>
</div>
<div class="output">
<div id="value"></div>
</div>

dynamically Adding and removing elements based on checkbox values with DOM

I'm just trying to dynamically add to a div within a form depending on which checkboxes are checked. So, I am creating the li tag and then they are added as li elements within an ol parent element so its just a list of values. I do not know what is wrong with my code, I'm not sure how to remove the appropriate value if the relevant checkbox is unchecked, and when I uncheck and then recheck a checkbox, it keeps adding the value over and over again.
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
input {
margin: 18px;
}
#o {
list-style-type: none;
}
.u {
list-style: none;
}
</style>
</head>
<body style="width: 700px">
<div style="float: left; width: 340px; height: 250px; border: 1px solid black; padding: 20px 0 10px 20px;">
<form id="myForm">
<ul class="u">
<li><input id="showAlert1" type="checkbox" name="thing" value="laptop">laptop</li>
<li><input id="showAlert2" type="checkbox" name="thing" value="iphone">iphone</li>
</ul>
</form>
</div>
<div id="myDiv" style="float: right; width: 317px; height: 250px; border: solid black; border-width: 1px 1px 1px 0; padding: 20px 0 10px 20px;">
<ol id="o">
</ol>
</div>
<script>
document.getElementById('myForm').addEventListener('change', function () {
var a = document.getElementsByName('thing');
for (var i = 0; i < a.length; i++) {
if (a[i].checked){
createDynamicElement();
} else if (!a[i].checked){
removeDynamicElement();
}
}
function createDynamicElement(){
var node = document.createElement("LI");
node.setAttribute("id1", "Hey");
var textnode = document.createTextNode(event.target.nextSibling.data);
node.appendChild(textnode);
document.getElementById("o").appendChild(node);
}
function removeDynamicElement() {
document.querySelector("#o li").innerHTML = "";
}
});
</script>
</body>
</html>
It looks like that you are adding an event listener to the form instead of the input elements themselves. I dont think the change event will be fired when an input element in a form changes. (see: https://developer.mozilla.org/en-US/docs/Web/Events/change)
On your event listener, try targeting the input elements themselves.
} else if (!a[i].checked){
removeDynamicElement();
}
...
function removeDynamicElement() {
document.querySelector("#o li").innerHTML = "";
}
Will empty the first or all matches(not sure) but wont remove them. Instead you should give li tags a unique ID and remove them completely via something like:
for (var i = 0; i < a.length; i++) {
if (a[i].checked){
console.log(a[i])
createDynamicElement(a[i].value);
} else if (!a[i].checked){
removeDynamicElement(a[i].value);
}
}
function createDynamicElement(id){
var node = document.createElement("LI");
node.setAttribute("id", id);
var textnode = document.createTextNode(id);
node.appendChild(textnode);
console.log(node)
document.getElementById("o").appendChild(node);
}
function removeDynamicElement(id) {
var target = document.getElementById(id)
target.parentElement.removeChild(target);
}
Or you could clear the ol completely on every change and repopulate it again like:
var a = document.getElementsByName('thing');
document.getElementById("o").innerHTML = null;
for (var i = 0; i < a.length; i++) {
if (a[i].checked){
console.log(a[i])
createDynamicElement(a[i].value);
}
}
function createDynamicElement(id){
var node = document.createElement("LI");
var textnode = document.createTextNode(id);
node.appendChild(textnode);
console.log(node)
document.getElementById("o").appendChild(node);
}
Edit:
A proper FIFO solution:
var a = document.getElementsByName('thing');
for (var i = 0; i < 2; i++) {
var target = document.getElementById(a[i].value);
if (a[i].checked && !target){
createDynamicElement(a[i].value);
} else if ((!a[i].checked) && target){
removeDynamicElement(a[i].value);
}
}
function createDynamicElement(id){
var node = document.createElement("li");
node.setAttribute("id", id);
var textnode = document.createTextNode(id);
node.appendChild(textnode);
document.getElementById("o").appendChild(node);
console.log("a")
}
function removeDynamicElement(id) {
target.parentElement.removeChild(target);
}
});

How to add and delete object in javascript?

I have order list in HTML :
<ol id="myList">
<li>Tea</li>
<li>Milk</li>
<li>Water</li>
</ol>
<button onclick="myFunction()">Try it</button>
And Ii write code in Javascript, and now I can add one item in this list. I have also set up limit of adding items. When I add one items, then how can I delete it?
<script>
var limit = 1
var currentAmount = 0;
function myFunction() {
//Check we haven't reached our limit.
if(currentAmount < limit){
var x = document.createElement("li");
var t = document.createTextNode("Coffee");
x.appendChild(t);
document.getElementById("myList").appendChild(x);
currentAmount++; //Increment our count
}
}
</script>
You could add remove button to every item in the list and attach onclick event to it that will call removeItem() function, check example below.
Hope this helps.
Snippet
var limit = 1
var currentAmount = 0;
function myFunction() {
//Check we haven't reached our limit.
if(currentAmount < limit){
var x = document.createElement("li");
var remove_btn = document.createElement("input");
remove_btn.setAttribute("type", "button");
remove_btn.setAttribute("value", "X");
remove_btn.setAttribute("onclick", "removeItem(this)");
x.appendChild(remove_btn);
var t = document.createTextNode("Coffee");
x.appendChild(t);
document.getElementById("myList").appendChild(x);
currentAmount++; //Increment our count
}
}
function removeItem() {
event.target.parentNode.remove();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol id="myList">
<li><button onclick="removeItem(this)">X</button> Tea</li>
<li><button onclick="removeItem(this)">X</button> Milk</li>
<li><button onclick="removeItem(this)">X</button> Water</li>
</ol>
<button onclick="myFunction()">Try it</button>
Well, it depends which element you want to remove, but for example, to remove the last element, add this button:
<button onClick="removeItem();">Now try this</button>
and this script:
function removeItem() {
document.getElementById("myList").lastChild.remove();
}
Got carried away, it removes items as OP requested and it:
Generates the delete button for every list item.
Added delete buttons for the old list items.
Added a text input so the user can input the list items.
Added an eventListener to the list in order to handle which button was clicked and save memory having one eventListener instead of one for each button.
Snippet
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Shopping List</title>
<style>
#inp1 {
margin: 10px 15px;
width: 25ex;
}
.item {
max-width: 30ex;
position: relative;
}
.del {
line-height: 1;
width: 7ex;
margin: 0 20px;
padding: 0 3px;
position: absolute;
right: -10px;
}
.del:before {
content: 'Delete';
font: inherit;
}
</style>
</head>
<body>
<h2>Shopping List</h2>
<ol id="list">
<li class="item">Tea
<button class="del"></button>
</li>
<li class="item">Milk
<button class="del"></button>
</li>
<li class="item">Water
<button class="del"></button>
</li>
</ol>
<input id="inp1" name="inp1" placeholder="Grocery Item" />
<button onclick="list(inp1.value)">Add</button>
<script>
var limit = 6
var currentAmount = 3;
var ol = document.getElementById("list");
function list(item) {
//Check we haven't reached our limit.
if (currentAmount < limit) {
var li = document.createElement("li");
var str = document.createTextNode(item);
var btn = document.createElement('button');
li.appendChild(str);
li.appendChild(btn);
li.classList.add('item');
btn.classList.add('del');
ol.appendChild(li);
currentAmount++; //Increment our count
}
return false;
}
ol.addEventListener('click', function(event) {
if (event.target != event.curentTarget) {
var tgt = event.target;
var li = tgt.parentElement;
ol.removeChild(li);
currentAmount--;
}
event.stopPropagation();
}, false);
</script>
</body>
</html>

Categories