I'm new to JS and I did this exercise for the course I'm taking. It's basically done, but I had to repeat the code that creates the "delete" button and I'm not sure how I can make this cleaner.
var button = document.getElementById("add")
var input = document.getElementById("userinput")
var ul = document.querySelector("ul")
var li = document.querySelectorAll("li")
function inputLength() {
return input.value.length;
}
function createListElement() {
let li = document.createElement("li")
li.appendChild(document.createTextNode(input.value))
ul.appendChild(li)
input.value = ""
// Create a delete button and configure it:
var btnDelete = document.createElement("button");
btnDelete.classList.add("delete");
btnDelete.textContent = "Delete";
// Append the button to the list item
li.appendChild(btnDelete);
}
// Create a delete button for each <li> already in the HTML file
li.forEach(function(item){
var btnDelete = document.createElement("button");
btnDelete.classList.add("delete");
btnDelete.textContent = "Delete";
item.appendChild(btnDelete);
});
function addListAfterClick() {
if(inputLength() > 0) {
createListElement()
}
}
function addListAfterKeypress(event) {
if(inputLength() > 0 && event.keyCode === 13) {
createListElement()
}
}
button.addEventListener("click", addListAfterClick)
input.addEventListener("keypress", addListAfterKeypress)
function toggleClassDoneOnAndOff(event) {
if (event.target.tagName === "LI") {
event.target.classList.toggle("done");
}
}
ul.addEventListener("click", toggleClassDoneOnAndOff);
function deleteAfterClick(event) {
// Determine if it was a delete button that was clicked
if(event.target.classList.contains("delete")){
// Remove the closest li ancestor to the clicked element
event.target.closest("li").remove();
}
}
// Handle all the clicks that originate from within the <ul> at
// the <ul> level when they bubble up to it instead of setting each
// button within the <ul> up with its own click event handler.
ul.addEventListener("click", deleteAfterClick);
.done {
text-decoration: line-through;
}
<body>
<h1>Shopping List</h1>
<p id="first">Get it done today</p>
<input id="userinput" type="text" placeholder="Add items">
<button id="add">Add</button>
<ul id="ul">
<li>Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
<script type="text/javascript" src="script.js"></script>
</body>
My question is that simple, but since Stack Overflow is telling me to "add some more details"...
Basically, I tried to turn this part into a function:
var btnDelete = document.createElement("button");
btnDelete.classList.add("delete");
btnDelete.textContent = "Delete";
But I couldn't figure out how to make it work inside the other ones.
You'll just extract those 3 lines into their own function and have that function return the newly created element. Where the lines are now will get replaced by the function call.
var button = document.getElementById("add")
var input = document.getElementById("userinput")
var ul = document.querySelector("ul")
var li = document.querySelectorAll("li")
function inputLength() {
return input.value.length;
}
function createDelete(){
// Create a delete button and configure it:
var btnDelete = document.createElement("button");
btnDelete.classList.add("delete");
btnDelete.textContent = "Delete";
return btnDelete; // <-- send the new element back to the function caller
}
function createListElement() {
let li = document.createElement("li")
li.appendChild(document.createTextNode(input.value))
ul.appendChild(li)
input.value = ""
// Append the button to the list item
// The createDelete() function will be called first
// and its return value (the new button) is what will
// be appended.
li.appendChild(createDelete());
}
// Create a delete button for each <li> already in the HTML file
li.forEach(function(item){
// The createDelete() function will be called first
// and its return value (the new button) is what will
// be appended.
item.appendChild(createDelete());
});
function addListAfterClick() {
if(inputLength() > 0) {
createListElement()
}
}
function addListAfterKeypress(event) {
if(inputLength() > 0 && event.keyCode === 13) {
createListElement()
}
}
button.addEventListener("click", addListAfterClick)
input.addEventListener("keypress", addListAfterKeypress)
function toggleClassDoneOnAndOff(event) {
if (event.target.tagName === "LI") {
event.target.classList.toggle("done");
}
}
ul.addEventListener("click", toggleClassDoneOnAndOff);
function deleteAfterClick(event) {
// Determine if it was a delete button that was clicked
if(event.target.classList.contains("delete")){
// Remove the closest li ancestor to the clicked element
event.target.closest("li").remove();
}
}
// Handle all the clicks that originate from within the <ul> at
// the <ul> level when they bubble up to it instead of setting each
// button within the <ul> up with its own click event handler.
ul.addEventListener("click", deleteAfterClick);
.done {
text-decoration: line-through;
}
<body>
<h1>Shopping List</h1>
<p id="first">Get it done today</p>
<input id="userinput" type="text" placeholder="Add items">
<button id="add">Add</button>
<ul id="ul">
<li>Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
<script type="text/javascript" src="script.js"></script>
</body>