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>
Related
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>
I'm trying to get the parent of the parent (div) of the li-element which I click and change/remove it's class but I don't know how to tell JS that it should get the specific li class that I click. Sorry for this simple question I'm fairly new to JS.
<!DOCTYPE html>
<html>
<body>
<p>List:</p>
<div class="div">
<ul>
<li class="lis">Coffee</li>
<li class="lis">Tea</li>
<li class="lis">Water</li>
</ul>
</div>
<script>
let li = document.getElementsByClassName("lis")
li.click() = function() {
var x = li.parentElement.parentElement.classList.value
if(x.classList.contains("div")) {
x.remove.classList("div")
}
}
</script>
</body>
</html>
<script>
var elements = document.getElementsByClassName("lis");
var myFunction = function(e) {
x = e.target.innerHTML;
e.target.parentElement.parentElement.innerHTML=x
};
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', myFunction, false);
}
</script>
You can use .closest() to select the closest div and after that, you can remove the class from that element.
Try below working code -
var elements = document.getElementsByClassName("lis");
var myFunction = function() {
var x = this.closest('.div')
if (x) {
this.closest('.div').classList.remove("div")
console.log('Div Element Class Removed!');
}
};
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', myFunction, false);
}
<!DOCTYPE html>
<html>
<body>
<p>List:</p>
<div class="div">
<ul>
<li class="lis">Coffee</li>
<li class="lis">Tea</li>
<li class="lis">Water</li>
</ul>
</div>
</body>
</html>
I recommend to delegate to the nearest static container
Also you had remove.classList - that should be classList.remove
Here I give an ID to the UL and test if the LI clicked has the lis class
document.getElementById("ul").addEventListener("click",function(e) {
const tgt = e.target.closest("li")
if (tgt.classList.contains("lis")) {
tgt.closest("div").classList.remove("div")
}
})
.div { background-color:red }
<p>List:</p>
<div class="div">
<ul id="ul">
<li class="lis">Coffee</li>
<li class="lis">Tea</li>
<li class="lis">Water</li>
</ul>
</div>
I came up with another good solution that let's me add and remove the div class, the parent of specified li elements. I added an extra div to make sure it always gets the certain parent that I've specified with .closest(body > div) and used a for loop to make the array that it creates select one certain li element, the one I currently click on.
<!DOCTYPE html>
<html>
<body>
<p>List:</p>
<div class="div">
<ul>
<li class="lis">Coffee</li>
<li class="lis">Tea</li>
<li class="lis">Water</li>
</ul>
</div>
<div>
<ul>
<li class="l">Coffee</li>
<li class="l">Tea</li>
<li class="l">Water</li>
</ul>
</div>
<script>
let lists = document.getElementsByClassName("lis");
let divs = document.getElementsByTagName("div");
for (let list of lists) {
list.addEventListener("click", () => {
list.closest("body > div")
for (let div of divs) {
div.addEventListener("click", () => {
if (div.classList.contains("div")) {
div.classList.remove("div")
} else {
div.classList.add("div")
}
})
}
})
}
</script>
<style>
.div {
color: brown;
font-size: larger;
}
</style>
</body>
</html>
var li = document.getElementsByClassName("lis");
for (var i=0; i<li.length; i++) {
li[i].onclick = function() {
var el = this.parentElement.parentElement;
if (el.className == "div") {
el.className = "";
}
}
}
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);
}
I'm trying to do a little practicing on my own, combining elements of Jon Duckett's JavaScript and JQuery book with those of Treehouse's JavaScript Basics track. Basically the program allows someone to type in text and see how much it would cost to make a sign with that text.
When I try to copy the text from the input element and place it next to custom sign, my input.value returns a zero. Any help would be greatly appreciated with figuring this out
var btnCalc = document.getElementById('myButton');
// Here's where I have the issue
var textInput = document.getElementById('textInput').value;
var customSign = document.getElementById('customSign');
var totalTiles = textInput.length;
var subtotal = totalTiles * 5;
var shipping = 7;
var grandTotal = subtotal + shipping;
btnCalc.addEventListener('click', Calculate);
function Calculate() {
// and here
document.getElementById('customSign').innerHTML = textInput;
document.getElementById('totalTiles').textContent = totalTiles;
document.getElementById('subtotal').textContent = subtotal;
document.getElementById('shipping').textContent = shipping;
document.getElementById('grandTotal').textContent = grandTotal;
}
h2 {
text-align: center;
}
span {
font-weight: bold;
}
div {
margin: 0 auto;
width: 400px;
overflow: auto;
}
ul {
list-style-type: none;
}
#right-col {
float: right;
}
#left-col {
float:left;
}
#input-form {
text-align: center;
}
<html>
<head>
<title>Duckett Chapter 2 Example</title>
<link href="styles.css" rel="stylesheet "type="text/css" >
</head>
<body>
<h2 id="greeting">Howdy Molly, please check your order: </h2>
<div>
<ul id="left-col">
<li><span>Custom Sign: </span> </li>
<li><span>Total Tiles: </span></li>
<li><span>Subtotal: </span></li>
<li><span>Shipping: </span></li>
<li><span>Grand Total: </span></li>
</ul>
<ul id="right-col">
<li id="customSign">Montague Hotel</li>
<li id="totalTiles">14</li>
<li id="subtotal">$70</li>
<li id="shipping">$7</li>
<li id="grandTotal">$77</li>
</ul>
<div id="input-form">
<input id="textInput" type="text">
<button id="myButton">Calculate</button>
</div>
</div>
<script src="scripts.js"></script>
</body>
</html>
Your variables have to be inside your function, otherwise their values are already empty when you call it.
var btnCalc = document.getElementById('myButton');
btnCalc.addEventListener('click', Calculate);
function Calculate() {
var textInput = document.getElementById('textInput').value;
var customSign = document.getElementById('customSign');
var totalTiles = textInput.length;
var subtotal = totalTiles * 5;
var shipping = 7;
var grandTotal = subtotal + shipping;
document.getElementById('customSign').innerHTML = textInput;
document.getElementById('totalTiles').textContent = totalTiles;
document.getElementById('subtotal').textContent = subtotal;
document.getElementById('shipping').textContent = shipping;
document.getElementById('grandTotal').textContent = grandTotal;
}
Move calculation part to the function.
var btnCalc = document.getElementById('myButton');
// Here's where I have the issue
var textInput = document.getElementById('textInput');
var customSign = document.getElementById('customSign');
btnCalc.addEventListener('click', Calculate);
function Calculate() {
var totalTiles = textInput.value.length;
var subtotal = totalTiles * 5;
var shipping = 7;
var grandTotal = subtotal + shipping;
// and here
document.getElementById('customSign').innerHTML = textInput.value;
document.getElementById('totalTiles').textContent = totalTiles;
document.getElementById('subtotal').textContent = subtotal;
document.getElementById('shipping').textContent = shipping;
document.getElementById('grandTotal').textContent = grandTotal;
}
h2 {
text-align: center;
}
span {
font-weight: bold;
}
div {
margin: 0 auto;
width: 400px;
overflow: auto;
}
ul {
list-style-type: none;
}
#right-col {
float: right;
}
#left-col {
float:left;
}
#input-form {
text-align: center;
}
<html>
<head>
<title>Duckett Chapter 2 Example</title>
<link href="styles.css" rel="stylesheet "type="text/css" >
</head>
<body>
<h2 id="greeting">Howdy Molly, please check your order: </h2>
<div>
<ul id="left-col">
<li><span>Custom Sign: </span> </li>
<li><span>Total Tiles: </span></li>
<li><span>Subtotal: </span></li>
<li><span>Shipping: </span></li>
<li><span>Grand Total: </span></li>
</ul>
<ul id="right-col">
<li id="customSign">Montague Hotel</li>
<li id="totalTiles">14</li>
<li id="subtotal">$70</li>
<li id="shipping">$7</li>
<li id="grandTotal">$77</li>
</ul>
<div id="input-form">
<input id="textInput" type="text">
<button id="myButton">Calculate</button>
</div>
</div>
<script src="scripts.js"></script>
</body>
</html>
I'm trying to create a drag and drop feature in HTML5 where I can drag from one list to another. I have one list with draggable items and another list with items that have drop events added. The problem is, regardless of what element I drop onto, the last drop event that was added is the one that gets called.
Thanks for any help or suggestions.
I've included my code below:
<!DOCTYPE html>
<head>
<title>List Conversion Test</title>
<style type="text/css">
#list, #cart {
display: inline;
float: left;
border: 1px solid #444;
margin: 25px;
padding: 10px;
}
#list p {
background-color: #036;
color: #fff;
}
#cart p {
background-color: #363;
color: #fff;
}
.listitem {
}
.listitem_done {
text-decoration: line-through;
}
.product {
background-color: #CCC;
}
.product_over {
background-color: #363;
}
</style>
<script type="text/javascript" src="http://html5demos.com/js/h5utils.js"></script>
</head>
<body>
<article>
<div id="list">
<p>On My List</p>
<ul>
<li class="listitem" id="L001">Shopping List Item #1</li>
<li class="listitem" id="L002">Shopping List Item #2</li>
</ul>
<div id="done">
<p>In My Cart</p>
<ul></ul>
</div>
</div>
<div id="cart">
<p>Cart</p>
<ul>
<li class="product" id="P001">Product #1</li>
<li class="product" id="P002">Product #2</li>
</ul>
</div>
</article>
<script>
// make list items draggable
var list = document.querySelectorAll('li.listitem'), thisItem = null;
for (var i = 0; i < list.length; i++) {
thisItem = list[i];
thisItem.setAttribute('draggable', 'true');
addEvent(thisItem, 'dragstart', function (e) {
e.dataTransfer.effectAllowed = 'copy';
e.dataTransfer.setData('Text', this.id);
});
}
// give products drop events
var products = document.querySelectorAll('li.product'), thisProduct = null;
for (var i = 0; i < products.length; i++) {
thisProduct = products[i];
addEvent(thisProduct, 'dragover', function (e) {
if (e.preventDefault) e.preventDefault();
this.className = 'product_over';
e.dataTransfer.dropEffect = 'copy';
return false;
});
addEvent(thisProduct, 'dragleave', function () {
this.className = 'product';
});
addEvent(thisProduct, 'drop', function (e) {
//alert(thisProduct.id);
if (e.stopPropagation) e.stopPropagation();
var thisItem = document.getElementById(e.dataTransfer.getData('Text'));
thisItem.parentNode.removeChild(thisItem);
thisProduct.className = 'product';
handleDrop(thisItem, thisProduct);
return false;
});
}
// handle the drop
function handleDrop(i, p) {
alert(i.id + ' to ' + p.id);
var done = document.querySelector('#done > ul');
done.appendChild(i);
i.className = 'listitem_done';
}
</script>
</body>
</html>
This is why it's often a bad idea to define functions (such as callback functions) within a loop. You're assigning thisProduct within the loop, but it will be reassigned for the next iteration of the loop. The way your closures are set up, each callback is bound to the same variable thisProduct, and will use the latest value.
One possible fix is to create a new closure where thisProduct is needed such as
(function(thisProduct) {
addEvent(thisProduct, 'drop', function (e) {
//alert(thisProduct.id);
if (e.stopPropagation) e.stopPropagation();
var thisItem = document.getElementById(e.dataTransfer.getData('Text'));
thisItem.parentNode.removeChild(thisItem);
thisProduct.className = 'product';
handleDrop(thisItem, thisProduct);
return false;
});
}(thisProduct));
This jsFiddle seems to work for me now. See here for more explanation.